Initial Weather service skeleton
This commit is contained in:
		
							parent
							
								
									6ba2878605
								
							
						
					
					
						commit
						bda96dc595
					
				
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@ -4,3 +4,6 @@
 | 
				
			|||||||
[submodule "src/libs/littlefs"]
 | 
					[submodule "src/libs/littlefs"]
 | 
				
			||||||
	path = src/libs/littlefs
 | 
						path = src/libs/littlefs
 | 
				
			||||||
	url = https://github.com/littlefs-project/littlefs.git
 | 
						url = https://github.com/littlefs-project/littlefs.git
 | 
				
			||||||
 | 
					[submodule "src/libs/QCBOR"]
 | 
				
			||||||
 | 
						path = src/libs/QCBOR
 | 
				
			||||||
 | 
						url = https://github.com/laurencelundblade/QCBOR.git
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
 | 
				
			|||||||
    alertNotificationClient {systemTask, notificationManager},
 | 
					    alertNotificationClient {systemTask, notificationManager},
 | 
				
			||||||
    currentTimeService {dateTimeController},
 | 
					    currentTimeService {dateTimeController},
 | 
				
			||||||
    musicService {systemTask},
 | 
					    musicService {systemTask},
 | 
				
			||||||
 | 
					    weatherService {systemTask, dateTimeController},
 | 
				
			||||||
    navService {systemTask},
 | 
					    navService {systemTask},
 | 
				
			||||||
    batteryInformationService {batteryController},
 | 
					    batteryInformationService {batteryController},
 | 
				
			||||||
    immediateAlertService {systemTask, notificationManager},
 | 
					    immediateAlertService {systemTask, notificationManager},
 | 
				
			||||||
@ -77,6 +78,7 @@ void NimbleController::Init() {
 | 
				
			|||||||
  currentTimeClient.Init();
 | 
					  currentTimeClient.Init();
 | 
				
			||||||
  currentTimeService.Init();
 | 
					  currentTimeService.Init();
 | 
				
			||||||
  musicService.Init();
 | 
					  musicService.Init();
 | 
				
			||||||
 | 
					  weatherService.Init();
 | 
				
			||||||
  navService.Init();
 | 
					  navService.Init();
 | 
				
			||||||
  anService.Init();
 | 
					  anService.Init();
 | 
				
			||||||
  dfuService.Init();
 | 
					  dfuService.Init();
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,7 @@
 | 
				
			|||||||
#include "components/ble/ServiceDiscovery.h"
 | 
					#include "components/ble/ServiceDiscovery.h"
 | 
				
			||||||
#include "components/ble/HeartRateService.h"
 | 
					#include "components/ble/HeartRateService.h"
 | 
				
			||||||
#include "components/ble/MotionService.h"
 | 
					#include "components/ble/MotionService.h"
 | 
				
			||||||
 | 
					#include "components/ble/weather/WeatherService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Pinetime {
 | 
					namespace Pinetime {
 | 
				
			||||||
  namespace Drivers {
 | 
					  namespace Drivers {
 | 
				
			||||||
@ -93,6 +94,7 @@ namespace Pinetime {
 | 
				
			|||||||
      AlertNotificationClient alertNotificationClient;
 | 
					      AlertNotificationClient alertNotificationClient;
 | 
				
			||||||
      CurrentTimeService currentTimeService;
 | 
					      CurrentTimeService currentTimeService;
 | 
				
			||||||
      MusicService musicService;
 | 
					      MusicService musicService;
 | 
				
			||||||
 | 
					      WeatherService weatherService;
 | 
				
			||||||
      NavigationService navService;
 | 
					      NavigationService navService;
 | 
				
			||||||
      BatteryInformationService batteryInformationService;
 | 
					      BatteryInformationService batteryInformationService;
 | 
				
			||||||
      ImmediateAlertService immediateAlertService;
 | 
					      ImmediateAlertService immediateAlertService;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										338
									
								
								src/components/ble/weather/WeatherData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								src/components/ble/weather/WeatherData.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,338 @@
 | 
				
			|||||||
 | 
					/*  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}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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,
 | 
				
			||||||
 | 
					        /** Extremely small, 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,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * 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
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * 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,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * 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
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Events have types
 | 
				
			||||||
 | 
					       * then they're easier to parse after sending them over the air
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      enum class eventtype {
 | 
				
			||||||
 | 
					        /** @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,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Valid event query
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      class valideventquery {
 | 
				
			||||||
 | 
					      public:
 | 
				
			||||||
 | 
					        static constexpr controlcodes code = controlcodes::HasValidEvent;
 | 
				
			||||||
 | 
					        eventtype eventType;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /** The header used for further parsing */
 | 
				
			||||||
 | 
					      class timelineheader {
 | 
				
			||||||
 | 
					      public:
 | 
				
			||||||
 | 
					        /** UNIX timestamp */
 | 
				
			||||||
 | 
					        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 */
 | 
				
			||||||
 | 
					        obscurationtype type;
 | 
				
			||||||
 | 
					        /** Visibility distance in meters */
 | 
				
			||||||
 | 
					        uint8_t amount;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /** Specifies how precipitation is stored */
 | 
				
			||||||
 | 
					      class precipitation : public timelineheader {
 | 
				
			||||||
 | 
					      public:
 | 
				
			||||||
 | 
					        /** Type */
 | 
				
			||||||
 | 
					        precipitationtype type;
 | 
				
			||||||
 | 
					        /** How much is it going to rain? In millimeters */
 | 
				
			||||||
 | 
					        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, microdegrees 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) */
 | 
				
			||||||
 | 
					        int16_t temperature;
 | 
				
			||||||
 | 
					        /** Dewpoint °C but multiplied by 100 (e.g. -12.50°C becomes -1250) */
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										208
									
								
								src/components/ble/weather/WeatherService.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								src/components/ble/weather/WeatherService.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,208 @@
 | 
				
			|||||||
 | 
					/*  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 conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
 | 
				
			||||||
 | 
					  return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(conn_handle, attr_handle, ctxt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Pinetime {
 | 
				
			||||||
 | 
					  namespace Controllers {
 | 
				
			||||||
 | 
					    WeatherService::WeatherService(System::SystemTask& system, DateTime& dateTimeController)
 | 
				
			||||||
 | 
					      : system(system), dateTimeController(dateTimeController) {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
 | 
				
			||||||
 | 
					      if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
 | 
				
			||||||
 | 
					        getCurrentPressure();
 | 
				
			||||||
 | 
					        tidyTimeline();
 | 
				
			||||||
 | 
					        getTimelineLength();
 | 
				
			||||||
 | 
					        const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
 | 
				
			||||||
 | 
					        if (packetLen <= 0) {
 | 
				
			||||||
 | 
					          return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Decode
 | 
				
			||||||
 | 
					        QCBORDecodeContext decodeContext;
 | 
				
			||||||
 | 
					        UsefulBufC EncodedCBOR;
 | 
				
			||||||
 | 
					        // TODO: Check uninit fine
 | 
				
			||||||
 | 
					        QCBORDecode_Init(&decodeContext, EncodedCBOR, QCBOR_DECODE_MODE_NORMAL);
 | 
				
			||||||
 | 
					        QCBORDecode_EnterMap(&decodeContext, nullptr);
 | 
				
			||||||
 | 
					        WeatherData::timelineheader timelineHeader {};
 | 
				
			||||||
 | 
					        // Always encodes to the smallest number of bytes based on the value
 | 
				
			||||||
 | 
					        QCBORDecode_GetInt64InMapSZ(&decodeContext, "Timestamp", reinterpret_cast<int64_t*>(&(timelineHeader.timestamp)));
 | 
				
			||||||
 | 
					        QCBORDecode_GetInt64InMapSZ(&decodeContext, "Expires", reinterpret_cast<int64_t*>(&(timelineHeader.expires)));
 | 
				
			||||||
 | 
					        QCBORDecode_GetInt64InMapSZ(&decodeContext, "EventType", reinterpret_cast<int64_t*>(&(timelineHeader.eventType)));
 | 
				
			||||||
 | 
					        switch (timelineHeader.eventType) {
 | 
				
			||||||
 | 
					            // TODO: Populate
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::AirQuality: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Obscuration: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Precipitation: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Wind: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Temperature: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Special: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Pressure: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Location: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          case WeatherData::eventtype::Clouds: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          default: {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        QCBORDecode_ExitMap(&decodeContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto uErr = QCBORDecode_Finish(&decodeContext);
 | 
				
			||||||
 | 
					        if (uErr != 0) {
 | 
				
			||||||
 | 
					          return BLE_ATT_ERR_INSUFFICIENT_RES;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
 | 
				
			||||||
 | 
					        // TODO: Detect control messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Encode
 | 
				
			||||||
 | 
					        uint8_t buffer[64];
 | 
				
			||||||
 | 
					        QCBOREncodeContext encodeContext;
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WeatherData::location WeatherService::getCurrentLocation() const {
 | 
				
			||||||
 | 
					      return WeatherData::location();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::clouds WeatherService::getCurrentClouds() const {
 | 
				
			||||||
 | 
					      return WeatherData::clouds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::obscuration WeatherService::getCurrentObscuration() const {
 | 
				
			||||||
 | 
					      return WeatherData::obscuration();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::precipitation WeatherService::getCurrentPrecipitation() const {
 | 
				
			||||||
 | 
					      return WeatherData::precipitation();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::wind WeatherService::getCurrentWind() const {
 | 
				
			||||||
 | 
					      return WeatherData::wind();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::temperature WeatherService::getCurrentTemperature() const {
 | 
				
			||||||
 | 
					      return WeatherData::temperature();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::humidity WeatherService::getCurrentHumidity() const {
 | 
				
			||||||
 | 
					      return WeatherData::humidity();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WeatherData::pressure WeatherService::getCurrentPressure() const {
 | 
				
			||||||
 | 
					      uint64_t currentTimestamp = getCurrentUNIXTimestamp();
 | 
				
			||||||
 | 
					      for (auto&& header : timeline) {
 | 
				
			||||||
 | 
					        if (header->eventType == WeatherData::eventtype::Pressure && header->timestamp + header->expires <= currentTimestamp) {
 | 
				
			||||||
 | 
					          return WeatherData::pressure();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return WeatherData::pressure();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WeatherData::airquality WeatherService::getCurrentQuality() const {
 | 
				
			||||||
 | 
					      return WeatherData::airquality();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 && header->timestamp + header->expires <= currentTimestamp) {
 | 
				
			||||||
 | 
					          // TODO: Check if its currently valid
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WeatherService::tidyTimeline() {
 | 
				
			||||||
 | 
					      uint64_t timeCurrent = 0;
 | 
				
			||||||
 | 
					      timeline.erase(std::remove_if(std::begin(timeline),
 | 
				
			||||||
 | 
					                                    std::end(timeline),
 | 
				
			||||||
 | 
					                                    [&](std::unique_ptr<WeatherData::timelineheader> const& header) {
 | 
				
			||||||
 | 
					                                      return header->timestamp + header->expires > 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint64_t WeatherService::getCurrentUNIXTimestamp() const {
 | 
				
			||||||
 | 
					      return std::chrono::duration_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime().time_since_epoch()).count();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										139
									
								
								src/components/ble/weather/WeatherService.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/components/ble/weather/WeatherService.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					/*  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 <components/datetime/DateTimeController.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 00030000-78fc-48fe-8e23-433b3a1942d0
 | 
				
			||||||
 | 
					#define WEATHER_SERVICE_UUID_BASE                                                                                                          \
 | 
				
			||||||
 | 
					  { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0x03, 0x00 }
 | 
				
			||||||
 | 
					#define WEATHER_SERVICE_CHAR_UUID(y, x)                                                                                                    \
 | 
				
			||||||
 | 
					  { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, (x), (y), 0x03, 0x00 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int WeatherCallback(uint16_t conn_handle, uint16_t attr_handle, 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 conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Helper functions for quick access to currently valid data
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      WeatherData::location getCurrentLocation() const;
 | 
				
			||||||
 | 
					      WeatherData::clouds getCurrentClouds() const;
 | 
				
			||||||
 | 
					      WeatherData::obscuration getCurrentObscuration() const;
 | 
				
			||||||
 | 
					      WeatherData::precipitation getCurrentPrecipitation() const;
 | 
				
			||||||
 | 
					      WeatherData::wind getCurrentWind() const;
 | 
				
			||||||
 | 
					      WeatherData::temperature getCurrentTemperature() const;
 | 
				
			||||||
 | 
					      WeatherData::humidity getCurrentHumidity() const;
 | 
				
			||||||
 | 
					      WeatherData::pressure getCurrentPressure() const;
 | 
				
			||||||
 | 
					      WeatherData::airquality getCurrentQuality() 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
 | 
				
			||||||
 | 
					       * @return
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      bool hasTimelineEventOfType(WeatherData::eventtype type) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					      ble_uuid128_t msUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_UUID_BASE};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Just write timeline data here
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      ble_uuid128_t wDataCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x01)};
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * This doesn't take timeline data
 | 
				
			||||||
 | 
					       * but provides some control over it
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      ble_uuid128_t wControlCharUuid {.u = {.type = BLE_UUID_TYPE_128}, .value = WEATHER_SERVICE_CHAR_UUID(0x00, 0x02)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const struct ble_gatt_chr_def characteristicDefinition[2] = {{.uuid = reinterpret_cast<ble_uuid_t*>(&wDataCharUuid),
 | 
				
			||||||
 | 
					                                                                    .access_cb = WeatherCallback,
 | 
				
			||||||
 | 
					                                                                    .arg = this,
 | 
				
			||||||
 | 
					                                                                    .flags = BLE_GATT_CHR_F_NOTIFY,
 | 
				
			||||||
 | 
					                                                                    .val_handle = &eventHandle},
 | 
				
			||||||
 | 
					                                                                   {.uuid = reinterpret_cast<ble_uuid_t*>(&wControlCharUuid),
 | 
				
			||||||
 | 
					                                                                    .access_cb = WeatherCallback,
 | 
				
			||||||
 | 
					                                                                    .arg = this,
 | 
				
			||||||
 | 
					                                                                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}};
 | 
				
			||||||
 | 
					      const struct ble_gatt_svc_def serviceDefinition[2] = {
 | 
				
			||||||
 | 
					        {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = reinterpret_cast<ble_uuid_t*>(&msUuid), .characteristics = characteristicDefinition},
 | 
				
			||||||
 | 
					        {0}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      uint16_t eventHandle {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Pinetime::System::SystemTask& system;
 | 
				
			||||||
 | 
					      Pinetime::Controllers::DateTime& dateTimeController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      std::vector<std::unique_ptr<WeatherData::timelineheader>> timeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Cleans up the timeline of expired events
 | 
				
			||||||
 | 
					       * @return result code
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      void tidyTimeline();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * Compares two timeline events
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      static bool compareTimelineEvents(const std::unique_ptr<WeatherData::timelineheader>& first,
 | 
				
			||||||
 | 
					                                        const std::unique_ptr<WeatherData::timelineheader>& second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      uint64_t getCurrentUNIXTimestamp() const;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										246
									
								
								src/displayapp/screens/Weather.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								src/displayapp/screens/Weather.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,246 @@
 | 
				
			|||||||
 | 
					#include "Weather.h"
 | 
				
			||||||
 | 
					#include <lvgl/lvgl.h>
 | 
				
			||||||
 | 
					#include "../DisplayApp.h"
 | 
				
			||||||
 | 
					#include "Label.h"
 | 
				
			||||||
 | 
					#include "Version.h"
 | 
				
			||||||
 | 
					#include "components/battery/BatteryController.h"
 | 
				
			||||||
 | 
					#include "components/ble/BleController.h"
 | 
				
			||||||
 | 
					#include "components/brightness/BrightnessController.h"
 | 
				
			||||||
 | 
					#include "components/datetime/DateTimeController.h"
 | 
				
			||||||
 | 
					#include "drivers/Watchdog.h"
 | 
				
			||||||
 | 
					#include "components/ble/weather/WeatherData.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace Pinetime::Applications::Screens;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Weather::Weather(Pinetime::Applications::DisplayApp* app,
 | 
				
			||||||
 | 
					                 Pinetime::Controllers::DateTime& dateTimeController,
 | 
				
			||||||
 | 
					                 Pinetime::Controllers::Battery& batteryController,
 | 
				
			||||||
 | 
					                 Pinetime::Controllers::BrightnessController& brightnessController,
 | 
				
			||||||
 | 
					                 Pinetime::Controllers::Ble& bleController,
 | 
				
			||||||
 | 
					                 Pinetime::Drivers::WatchdogView& watchdog)
 | 
				
			||||||
 | 
					  : Screen(app),
 | 
				
			||||||
 | 
					    dateTimeController {dateTimeController},
 | 
				
			||||||
 | 
					    batteryController {batteryController},
 | 
				
			||||||
 | 
					    brightnessController {brightnessController},
 | 
				
			||||||
 | 
					    bleController {bleController},
 | 
				
			||||||
 | 
					    watchdog {watchdog},
 | 
				
			||||||
 | 
					    screens {app,
 | 
				
			||||||
 | 
					             0,
 | 
				
			||||||
 | 
					             {[this]() -> std::unique_ptr<Screen> {
 | 
				
			||||||
 | 
					                return CreateScreen1();
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              [this]() -> std::unique_ptr<Screen> {
 | 
				
			||||||
 | 
					                return CreateScreen2();
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              [this]() -> std::unique_ptr<Screen> {
 | 
				
			||||||
 | 
					                return CreateScreen3();
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              [this]() -> std::unique_ptr<Screen> {
 | 
				
			||||||
 | 
					                return CreateScreen4();
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              [this]() -> std::unique_ptr<Screen> {
 | 
				
			||||||
 | 
					                return CreateScreen5();
 | 
				
			||||||
 | 
					              }},
 | 
				
			||||||
 | 
					             Screens::ScreenListModes::UpDown} {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Weather::~Weather() {
 | 
				
			||||||
 | 
					  lv_obj_clean(lv_scr_act());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Weather::Refresh() {
 | 
				
			||||||
 | 
					  if (running) {
 | 
				
			||||||
 | 
					    screens.Refresh();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return running;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Weather::OnButtonPushed() {
 | 
				
			||||||
 | 
					  running = false;
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Weather::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
 | 
				
			||||||
 | 
					  return screens.OnTouchEvent(event);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Screen> Weather::CreateScreen1() {
 | 
				
			||||||
 | 
					  lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
 | 
				
			||||||
 | 
					  lv_label_set_recolor(label, true);
 | 
				
			||||||
 | 
					  lv_label_set_text_fmt(label,
 | 
				
			||||||
 | 
					                        "#FFFF00 InfiniTime#\n\n"
 | 
				
			||||||
 | 
					                        "#444444 Version# %ld.%ld.%ld\n\n"
 | 
				
			||||||
 | 
					                        "#444444 Build date#\n"
 | 
				
			||||||
 | 
					                        "%s\n"
 | 
				
			||||||
 | 
					                        "%s\n",
 | 
				
			||||||
 | 
					                        Version::Major(),
 | 
				
			||||||
 | 
					                        Version::Minor(),
 | 
				
			||||||
 | 
					                        Version::Patch(),
 | 
				
			||||||
 | 
					                        __DATE__,
 | 
				
			||||||
 | 
					                        __TIME__);
 | 
				
			||||||
 | 
					  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::CreateScreen2() {
 | 
				
			||||||
 | 
					  auto batteryPercent = static_cast<uint8_t>(batteryController.PercentRemaining());
 | 
				
			||||||
 | 
					  float batteryVoltage = batteryController.Voltage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto resetReason = [this]() {
 | 
				
			||||||
 | 
					    switch (watchdog.ResetReason()) {
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::Watchdog:
 | 
				
			||||||
 | 
					        return "wtdg";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::HardReset:
 | 
				
			||||||
 | 
					        return "hardr";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::NFC:
 | 
				
			||||||
 | 
					        return "nfc";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::SoftReset:
 | 
				
			||||||
 | 
					        return "softr";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::CpuLockup:
 | 
				
			||||||
 | 
					        return "cpulock";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::SystemOff:
 | 
				
			||||||
 | 
					        return "off";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::LpComp:
 | 
				
			||||||
 | 
					        return "lpcomp";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::DebugInterface:
 | 
				
			||||||
 | 
					        return "dbg";
 | 
				
			||||||
 | 
					      case Drivers::Watchdog::ResetReasons::ResetPin:
 | 
				
			||||||
 | 
					        return "rst";
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        return "?";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // uptime
 | 
				
			||||||
 | 
					  static constexpr uint32_t secondsInADay = 60 * 60 * 24;
 | 
				
			||||||
 | 
					  static constexpr uint32_t secondsInAnHour = 60 * 60;
 | 
				
			||||||
 | 
					  static constexpr uint32_t secondsInAMinute = 60;
 | 
				
			||||||
 | 
					  uint32_t uptimeSeconds = dateTimeController.Uptime().count();
 | 
				
			||||||
 | 
					  uint32_t uptimeDays = (uptimeSeconds / secondsInADay);
 | 
				
			||||||
 | 
					  uptimeSeconds = uptimeSeconds % secondsInADay;
 | 
				
			||||||
 | 
					  uint32_t uptimeHours = uptimeSeconds / secondsInAnHour;
 | 
				
			||||||
 | 
					  uptimeSeconds = uptimeSeconds % secondsInAnHour;
 | 
				
			||||||
 | 
					  uint32_t uptimeMinutes = uptimeSeconds / secondsInAMinute;
 | 
				
			||||||
 | 
					  uptimeSeconds = uptimeSeconds % secondsInAMinute;
 | 
				
			||||||
 | 
					  // TODO handle more than 100 days of uptime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (batteryPercent == -1)
 | 
				
			||||||
 | 
					    batteryPercent = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // hack to not use the flot functions from printf
 | 
				
			||||||
 | 
					  uint8_t batteryVoltageBytes[2];
 | 
				
			||||||
 | 
					  batteryVoltageBytes[1] = static_cast<uint8_t>(batteryVoltage); // truncate whole numbers
 | 
				
			||||||
 | 
					  batteryVoltageBytes[0] =
 | 
				
			||||||
 | 
					    static_cast<uint8_t>((batteryVoltage - batteryVoltageBytes[1]) * 100); // remove whole part of flt and shift 2 places over
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
 | 
				
			||||||
 | 
					  lv_label_set_recolor(label, true);
 | 
				
			||||||
 | 
					  lv_label_set_text_fmt(label,
 | 
				
			||||||
 | 
					                        "#444444 Date# %02d/%02d/%04d\n"
 | 
				
			||||||
 | 
					                        "#444444 Time# %02d:%02d:%02d\n"
 | 
				
			||||||
 | 
					                        "#444444 Uptime#\n %02lud %02lu:%02lu:%02lu\n"
 | 
				
			||||||
 | 
					                        "#444444 Battery# %d%%/%1i.%02iv\n"
 | 
				
			||||||
 | 
					                        "#444444 Backlight# %s\n"
 | 
				
			||||||
 | 
					                        "#444444 Last reset# %s\n",
 | 
				
			||||||
 | 
					                        dateTimeController.Day(),
 | 
				
			||||||
 | 
					                        static_cast<uint8_t>(dateTimeController.Month()),
 | 
				
			||||||
 | 
					                        dateTimeController.Year(),
 | 
				
			||||||
 | 
					                        dateTimeController.Hours(),
 | 
				
			||||||
 | 
					                        dateTimeController.Minutes(),
 | 
				
			||||||
 | 
					                        dateTimeController.Seconds(),
 | 
				
			||||||
 | 
					                        uptimeDays,
 | 
				
			||||||
 | 
					                        uptimeHours,
 | 
				
			||||||
 | 
					                        uptimeMinutes,
 | 
				
			||||||
 | 
					                        uptimeSeconds,
 | 
				
			||||||
 | 
					                        batteryPercent,
 | 
				
			||||||
 | 
					                        batteryVoltageBytes[1],
 | 
				
			||||||
 | 
					                        batteryVoltageBytes[0],
 | 
				
			||||||
 | 
					                        brightnessController.ToString(),
 | 
				
			||||||
 | 
					                        resetReason);
 | 
				
			||||||
 | 
					  lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
 | 
				
			||||||
 | 
					  return std::unique_ptr<Screen>(new Screens::Label(1, 4, app, label));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::unique_ptr<Screen> Weather::CreateScreen3() {
 | 
				
			||||||
 | 
					  lv_mem_monitor_t mon;
 | 
				
			||||||
 | 
					  lv_mem_monitor(&mon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
 | 
				
			||||||
 | 
					  lv_label_set_recolor(label, true);
 | 
				
			||||||
 | 
					  auto& bleAddr = bleController.Address();
 | 
				
			||||||
 | 
					  lv_label_set_text_fmt(label,
 | 
				
			||||||
 | 
					                        "#444444 BLE MAC#\n"
 | 
				
			||||||
 | 
					                        " %02x:%02x:%02x:%02x:%02x:%02x"
 | 
				
			||||||
 | 
					                        "\n"
 | 
				
			||||||
 | 
					                        "#444444 Memory#\n"
 | 
				
			||||||
 | 
					                        " #444444 used# %d (%d%%)\n"
 | 
				
			||||||
 | 
					                        " #444444 frag# %d%%\n"
 | 
				
			||||||
 | 
					                        " #444444 free# %d"
 | 
				
			||||||
 | 
					                        "\n"
 | 
				
			||||||
 | 
					                        "#444444 Steps# %li",
 | 
				
			||||||
 | 
					                        bleAddr[5],
 | 
				
			||||||
 | 
					                        bleAddr[4],
 | 
				
			||||||
 | 
					                        bleAddr[3],
 | 
				
			||||||
 | 
					                        bleAddr[2],
 | 
				
			||||||
 | 
					                        bleAddr[1],
 | 
				
			||||||
 | 
					                        bleAddr[0],
 | 
				
			||||||
 | 
					                        (int) mon.total_size - mon.free_size,
 | 
				
			||||||
 | 
					                        mon.used_pct,
 | 
				
			||||||
 | 
					                        mon.frag_pct,
 | 
				
			||||||
 | 
					                        (int) mon.free_biggest_size,
 | 
				
			||||||
 | 
					                        0);
 | 
				
			||||||
 | 
					  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() {
 | 
				
			||||||
 | 
					  TaskStatus_t tasksStatus[7];
 | 
				
			||||||
 | 
					  lv_obj_t* infoTask = lv_table_create(lv_scr_act(), NULL);
 | 
				
			||||||
 | 
					  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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr);
 | 
				
			||||||
 | 
					  std::sort(tasksStatus, tasksStatus + nb, sortById);
 | 
				
			||||||
 | 
					  for (uint8_t i = 0; i < nb; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lv_table_set_cell_value(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
 | 
				
			||||||
 | 
					    lv_table_set_cell_value(infoTask, i + 1, 1, tasksStatus[i].pcTaskName);
 | 
				
			||||||
 | 
					    if (tasksStatus[i].usStackHighWaterMark < 20) {
 | 
				
			||||||
 | 
					      std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
 | 
				
			||||||
 | 
					      lv_table_set_cell_value(infoTask, i + 1, 2, str1.c_str());
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  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_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
 | 
				
			||||||
 | 
					  return std::unique_ptr<Screen>(new Screens::Label(4, 5, app, label));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/displayapp/screens/Weather.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/displayapp/screens/Weather.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include "Screen.h"
 | 
				
			||||||
 | 
					#include "ScreenList.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Pinetime {
 | 
				
			||||||
 | 
					  namespace Controllers {
 | 
				
			||||||
 | 
					    class DateTime;
 | 
				
			||||||
 | 
					    class Battery;
 | 
				
			||||||
 | 
					    class BrightnessController;
 | 
				
			||||||
 | 
					    class Ble;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  namespace Drivers {
 | 
				
			||||||
 | 
					    class WatchdogView;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  namespace Applications {
 | 
				
			||||||
 | 
					    class DisplayApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    namespace Screens {
 | 
				
			||||||
 | 
					      class Weather : public Screen {
 | 
				
			||||||
 | 
					      public:
 | 
				
			||||||
 | 
					        explicit Weather(DisplayApp* app,
 | 
				
			||||||
 | 
					                         Pinetime::Controllers::DateTime& dateTimeController,
 | 
				
			||||||
 | 
					                         Pinetime::Controllers::Battery& batteryController,
 | 
				
			||||||
 | 
					                         Pinetime::Controllers::BrightnessController& brightnessController,
 | 
				
			||||||
 | 
					                         Pinetime::Controllers::Ble& bleController,
 | 
				
			||||||
 | 
					                         Pinetime::Drivers::WatchdogView& watchdog);
 | 
				
			||||||
 | 
					        ~Weather() override;
 | 
				
			||||||
 | 
					        bool Refresh() override;
 | 
				
			||||||
 | 
					        bool OnButtonPushed() override;
 | 
				
			||||||
 | 
					        bool OnTouchEvent(TouchEvents event) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      private:
 | 
				
			||||||
 | 
					        bool running = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Pinetime::Controllers::DateTime& dateTimeController;
 | 
				
			||||||
 | 
					        Pinetime::Controllers::Battery& batteryController;
 | 
				
			||||||
 | 
					        Pinetime::Controllers::BrightnessController& brightnessController;
 | 
				
			||||||
 | 
					        Pinetime::Controllers::Ble& bleController;
 | 
				
			||||||
 | 
					        Pinetime::Drivers::WatchdogView& watchdog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ScreenList<5> screens;
 | 
				
			||||||
 | 
					        std::unique_ptr<Screen> CreateScreen1();
 | 
				
			||||||
 | 
					        std::unique_ptr<Screen> CreateScreen2();
 | 
				
			||||||
 | 
					        std::unique_ptr<Screen> CreateScreen3();
 | 
				
			||||||
 | 
					        std::unique_ptr<Screen> CreateScreen4();
 | 
				
			||||||
 | 
					        std::unique_ptr<Screen> CreateScreen5();
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user