Skip to content

Commit bda96dc

Browse files
committed
Initial Weather service skeleton
1 parent 6ba2878 commit bda96dc

File tree

8 files changed

+992
-0
lines changed

8 files changed

+992
-0
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "src/libs/littlefs"]
55
path = src/libs/littlefs
66
url = https://github.com/littlefs-project/littlefs.git
7+
[submodule "src/libs/QCBOR"]
8+
path = src/libs/QCBOR
9+
url = https://github.com/laurencelundblade/QCBOR.git

src/components/ble/NimbleController.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
3636
alertNotificationClient {systemTask, notificationManager},
3737
currentTimeService {dateTimeController},
3838
musicService {systemTask},
39+
weatherService {systemTask, dateTimeController},
3940
navService {systemTask},
4041
batteryInformationService {batteryController},
4142
immediateAlertService {systemTask, notificationManager},
@@ -77,6 +78,7 @@ void NimbleController::Init() {
7778
currentTimeClient.Init();
7879
currentTimeService.Init();
7980
musicService.Init();
81+
weatherService.Init();
8082
navService.Init();
8183
anService.Init();
8284
dfuService.Init();

src/components/ble/NimbleController.h

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "components/ble/ServiceDiscovery.h"
2121
#include "components/ble/HeartRateService.h"
2222
#include "components/ble/MotionService.h"
23+
#include "components/ble/weather/WeatherService.h"
2324

2425
namespace Pinetime {
2526
namespace Drivers {
@@ -93,6 +94,7 @@ namespace Pinetime {
9394
AlertNotificationClient alertNotificationClient;
9495
CurrentTimeService currentTimeService;
9596
MusicService musicService;
97+
WeatherService weatherService;
9698
NavigationService navService;
9799
BatteryInformationService batteryInformationService;
98100
ImmediateAlertService immediateAlertService;
+338
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
/* Copyright (C) 2021 Avamander
2+
3+
This file is part of InfiniTime.
4+
5+
InfiniTime is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published
7+
by the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
InfiniTime is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
#pragma once
19+
20+
/**
21+
* Different weather events, weather data structures used by {@link WeatherService.h}
22+
*
23+
*
24+
* Implemented based on and other material:
25+
* https://en.wikipedia.org/wiki/METAR
26+
* https://www.weather.gov/jetstream/obscurationtypes
27+
* http://www.faraim.org/aim/aim-4-03-14-493.html
28+
*/
29+
30+
namespace Pinetime {
31+
namespace Controllers {
32+
class WeatherData {
33+
public:
34+
/**
35+
* Visibility obscuration types
36+
*/
37+
enum class obscurationtype {
38+
/** No obscuration */
39+
None = 0,
40+
/** Water particles suspended in the air; low visibility; does not fall */
41+
Fog = 1,
42+
/** Extremely small, dry particles in the air; invisible to the eye; opalescent */
43+
Haze = 2,
44+
/** Small fire-created particles suspended in the air */
45+
Smoke = 3,
46+
/** Fine rock powder, from for example volcanoes */
47+
Ash = 4,
48+
/** Fine particles of earth suspended in the air by the wind */
49+
Dust = 5,
50+
/** Fine particles of sand suspended in the air by the wind */
51+
Sand = 6,
52+
/** Water particles suspended in the air; low-ish visibility; temperature is near dewpoint */
53+
Mist = 7,
54+
};
55+
56+
/**
57+
* Types of precipitation
58+
*/
59+
enum class precipitationtype {
60+
/**
61+
* No precipitation
62+
*
63+
* Theoretically we could just _not_ send the event, but then
64+
* how do we differentiate between no precipitation and
65+
* no information about precipitation
66+
*/
67+
None = 0,
68+
/** Drops larger than a drizzle; also widely separated drizzle */
69+
Rain = 1,
70+
/** Fairly uniform rain consisting of fine drops */
71+
Drizzle = 2,
72+
/** Rain that freezes upon contact with objects and ground */
73+
FreezingRain = 3,
74+
/** Rain + hail; ice pellets; small translucent frozen raindrops */
75+
Sleet = 4,
76+
/** Larger ice pellets; falling separately or in irregular clumps */
77+
Hail = 5,
78+
/** Hail with smaller grains of ice; mini-snowballs */
79+
SmallHail = 6,
80+
/** Snow... */
81+
Snow = 7,
82+
/** Frozen drizzle; very small snow crystals */
83+
SnowGrains = 8,
84+
/** Needles; columns or plates of ice. Sometimes described as "diamond dust". In very cold regions */
85+
IceCrystals = 9
86+
};
87+
88+
/**
89+
* These are special events that can "enhance" the "experience" of existing weather events
90+
*/
91+
enum class specialtype {
92+
/** Strong wind with a sudden onset that lasts at least a minute */
93+
Squall = 0,
94+
/** Series of waves in a water body caused by the displacement of a large volume of water */
95+
Tsunami = 1,
96+
/** Violent; rotating column of air */
97+
Tornado = 2,
98+
/** Unplanned; unwanted; uncontrolled fire in an area */
99+
Fire = 3,
100+
/** Thunder and/or lightning */
101+
Thunder = 4,
102+
};
103+
104+
/**
105+
* These are used for weather timeline manipulation
106+
* that isn't just adding to the stack of weather events
107+
*/
108+
enum class controlcodes {
109+
/** How much is stored already */
110+
GetLength = 0,
111+
/** This wipes the entire timeline */
112+
DelTimeline = 1,
113+
/** There's a currently valid timeline event with the given type */
114+
HasValidEvent = 3
115+
};
116+
117+
/**
118+
* Events have types
119+
* then they're easier to parse after sending them over the air
120+
*/
121+
enum class eventtype {
122+
/** @see obscuration */
123+
Obscuration = 0,
124+
/** @see precipitation */
125+
Precipitation = 1,
126+
/** @see wind */
127+
Wind = 2,
128+
/** @see temperature */
129+
Temperature = 3,
130+
/** @see airquality */
131+
AirQuality = 4,
132+
/** @see special */
133+
Special = 5,
134+
/** @see pressure */
135+
Pressure = 6,
136+
/** @see location */
137+
Location = 7,
138+
/** @see cloud */
139+
Clouds = 8,
140+
};
141+
142+
/**
143+
* Valid event query
144+
*/
145+
class valideventquery {
146+
public:
147+
static constexpr controlcodes code = controlcodes::HasValidEvent;
148+
eventtype eventType;
149+
};
150+
151+
/** The header used for further parsing */
152+
class timelineheader {
153+
public:
154+
/** UNIX timestamp */
155+
uint64_t timestamp;
156+
/**
157+
* Time in seconds until the event expires
158+
*
159+
* 32 bits ought to be enough for everyone
160+
*
161+
* If there's a newer event of the same type then it overrides this one, even if it hasn't expired
162+
*/
163+
uint32_t expires;
164+
/**
165+
* What type of weather-related event
166+
*/
167+
eventtype eventType;
168+
};
169+
170+
/** Specifies how cloudiness is stored */
171+
class clouds : public timelineheader {
172+
public:
173+
/** Cloud coverage in percentage, 0-100% */
174+
uint8_t amount;
175+
};
176+
177+
/** Specifies how obscuration is stored */
178+
class obscuration : public timelineheader {
179+
public:
180+
/** Type */
181+
obscurationtype type;
182+
/** Visibility distance in meters */
183+
uint8_t amount;
184+
};
185+
186+
/** Specifies how precipitation is stored */
187+
class precipitation : public timelineheader {
188+
public:
189+
/** Type */
190+
precipitationtype type;
191+
/** How much is it going to rain? In millimeters */
192+
uint8_t amount;
193+
};
194+
195+
/**
196+
* How wind speed is stored
197+
*
198+
* In order to represent bursts of wind instead of constant wind,
199+
* you have minimum and maximum speeds.
200+
*
201+
* As direction can fluctuate wildly and some watchfaces might wish to display it nicely,
202+
* we're following the aerospace industry weather report option of specifying a range.
203+
*/
204+
class wind : public timelineheader {
205+
public:
206+
/** Meters per second */
207+
uint8_t speedMin;
208+
/** Meters per second */
209+
uint8_t speedMax;
210+
/** Unitless direction between 0-255; approximately 1 unit per 0.71 degrees */
211+
uint8_t directionMin;
212+
/** Unitless direction between 0-255; approximately 1 unit per 0.71 degrees */
213+
uint8_t directionMax;
214+
};
215+
216+
/**
217+
* How temperature is stored
218+
*
219+
* As it's annoying to figure out the dewpoint on the watch,
220+
* please send it from the companion
221+
*
222+
* We don't do floats, microdegrees are not useful. Make sure to multiply.
223+
*/
224+
class temperature : public timelineheader {
225+
public:
226+
/** Temperature °C but multiplied by 100 (e.g. -12.50°C becomes -1250) */
227+
int16_t temperature;
228+
/** Dewpoint °C but multiplied by 100 (e.g. -12.50°C becomes -1250) */
229+
int16_t dewPoint;
230+
};
231+
232+
/**
233+
* How location info is stored
234+
*
235+
* This can be mostly static with long expiration,
236+
* as it usually is, but it could change during a trip for ex.
237+
* so we allow changing it dynamically.
238+
*
239+
* Location info can be for some kind of map watchface
240+
* or daylight calculations, should those be required.
241+
*
242+
*/
243+
class location : public timelineheader {
244+
public:
245+
/** Location name */
246+
std::string location;
247+
/** Altitude relative to sea level in meters */
248+
int16_t altitude;
249+
/** Latitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */
250+
int32_t latitude;
251+
/** Longitude, EPSG:3857 (Google Maps, Openstreetmaps datum) */
252+
int32_t longitude;
253+
};
254+
255+
/**
256+
* How humidity is stored
257+
*/
258+
class humidity : public timelineheader {
259+
public:
260+
/** Relative humidity, 0-100% */
261+
uint8_t humidity;
262+
};
263+
264+
/**
265+
* How air pressure is stored
266+
*/
267+
class pressure : public timelineheader {
268+
public:
269+
/** Air pressure in hectopascals (hPa) */
270+
int16_t pressure;
271+
};
272+
273+
/**
274+
* How special events are stored
275+
*/
276+
class special : public timelineheader {
277+
public:
278+
/** Special event's type */
279+
specialtype type;
280+
};
281+
282+
/**
283+
* How air quality is stored
284+
*
285+
* These events are a bit more complex because the topic is not simple,
286+
* the intention is to heavy-lift the annoying preprocessing from the watch
287+
* this allows watchface or watchapp makers to generate accurate alerts and graphics
288+
*
289+
* If this needs further enforced standardization, pull requests are welcome
290+
*/
291+
class airquality : public timelineheader {
292+
public:
293+
/**
294+
* The name of the pollution
295+
*
296+
* for the sake of better compatibility with watchapps
297+
* that might want to use this data for say visuals
298+
* don't localize the name.
299+
*
300+
* Ideally watchapp itself localizes the name, if it's at all needed.
301+
*
302+
* E.g.
303+
* For generic ones use "PM0.1", "PM5", "PM10"
304+
* For chemical compounds use the molecular formula e.g. "NO2", "CO2", "O3"
305+
* For pollen use the genus, e.g. "Betula" for birch or "Alternaria" for that mold's spores
306+
*/
307+
std::string polluter;
308+
/**
309+
* Amount of the pollution in SI units,
310+
* otherwise it's going to be difficult to create UI, alerts
311+
* and so on and for.
312+
*
313+
* See more:
314+
* https://ec.europa.eu/environment/air/quality/standards.htm
315+
* http://www.ourair.org/wp-content/uploads/2012-aaqs2.pdf
316+
*
317+
* Example units:
318+
* count/m³ for pollen
319+
* µgC/m³ for micrograms of organic carbon
320+
* µg/m³ sulfates, PM0.1, PM1, PM2, PM10 and so on, dust
321+
* mg/m³ CO2, CO
322+
* ng/m³ for heavy metals
323+
*
324+
* List is not comprehensive, should be improved.
325+
* The current ones are what watchapps assume.
326+
*
327+
* Note: ppb and ppm to concentration should be calculated on the companion, using
328+
* the correct formula (taking into account temperature and air pressure)
329+
*
330+
* Note2: The amount is off by times 100, for two decimal places of precision.
331+
* E.g. 54.32µg/m³ is 5432
332+
*
333+
*/
334+
uint32_t amount;
335+
};
336+
};
337+
}
338+
}

0 commit comments

Comments
 (0)