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