Pocobo_2.ino 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. /*Pocobo 2- Pollution Collecting Bottle 2
  2. *
  3. * v1.0 (13.06.2025)
  4. *
  5. * Devices & Parts:
  6. * - Arduino MKR NB 1500 (https://www.arduino.cc/en/Guide/MKRNB1500, https://store.arduino.cc/products/arduino-mkr-nb-1500?_gl=1%2Ajmo3e2%2A_ga%2AMTgyMjQxNTg5MC4xNjM3MTQ1NTIw%2A_ga_NEXN8H46L5%2AMTYzNzc0NjM2My4yLjEuMTYzNzc0NjYwOS4w)
  7. * - Sensirion SEN54 PM Sensor (https://www.sensirion.com/products/catalog/SEN54)
  8. * - Adafruit Mini GPS PA1010D Module (https://learn.adafruit.com/adafruit-mini-gps-pa1010d-module)
  9. * - Dipole Pentaband Waterproff antenna (https://store.arduino.cc/en-at/products/dipole-pentaband-waterproof-antenna?queryID=undefined
  10. * - Eckstein 3.7V, 2000mAh Battery (https://eckstein-shop.de/LiPo-Akku-Lithium-Ion-Polymer-Batterie-37V-2000mAh-mit-JST-PHR-2-Stecker-LP803860)
  11. * - Adafruit Powerboost 500 Charger (https://www.adafruit.com/product/1944) (needed because the Arduino MKR NB can only charge batteries from 700-1500mAh; see also (scroll down): https://store.arduino.cc/products/arduino-mkr-nb-1500?_gl=1%2Ads0y0w%2A_ga%2AMTgyMjQxNTg5MC4xNjM3MTQ1NTIw%2A_ga_NEXN8H46L5%2AMTYzODQ1MzI5My4xNy4xLjE2Mzg0NTUwMzkuMA..)
  12. * - Adafruit RGB On/Off Switch (https://www.adafruit.com/product/3426)
  13. *
  14. *
  15. *
  16. * Infos & Libraries:
  17. * - Arduino MKR NB Library:https://www.arduino.cc/en/Reference/MKRNB
  18. * - Arduino MKR NB Features: https://docs.arduino.cc/hardware/mkr-nb-1500
  19. * - Sensirion SEN54 Library Github: https://github.com/Sensirion/arduino-i2c-sen5x
  20. * - Sensirion SEN54 Library Arduino: https://www.arduino.cc/reference/en/libraries/sensirion-i2c-sen5x/
  21. * - Comparison for PM2.5 values: https://kachelmannwetter.com/de/luftqualitaet/wien-umgebung/pm25-feinstaub/20211126-1100z.html
  22. * - Comparison for PM10 values: https://kachelmannwetter.com/de/luftqualitaet/wien-umgebung/pm10-feinstaub/20211126-1100z.html
  23. * - Available Radio Access Technology: https://www.gsma.com/iot/deployment-map/
  24. * - Sparkfun_I2C_GPS_Arduino_Library: For using TinyGPS++ Library with I2C
  25. * - Tiny GPS++ Library: http://arduiniana.org/libraries/tinygpsplus/
  26. * - Switch with Powerboost 500: https://learn.adafruit.com/adafruit-powerboost-500-plus-charger/on-slash-off-switch
  27. * - Wiring the Button: https://learn.adafruit.com/ambient-color-controller/build-the-circuit
  28. * - Example for lighting the button LED: https://create.arduino.cc/projecthub/102550/rgb-light-control-with-arduino-9979df
  29. * - Read Battery voltage on MKR Board: https://docs.arduino.cc/tutorials/mkr-wifi-1010/mkr-battery-app-note
  30. * - TinyGPS++ i2c example: https://github.com/sparkfun/SparkFun_GPS_Breakout_XA1110_Qwiic/blob/master/Libraries/SparkFun%20I2C%20GPS/examples/Example2-TinyGPS/Example2-TinyGPS.ino
  31. *
  32. * WIRING:
  33. * Arduino SCL <-> SCL Adafruit Mini GPS, SEN54 (4, yellow)
  34. * Arduino SDA <-> SDA Adafruit Mini GPS, SEN54 (3, green)
  35. * Arduino VIN <-> 5V
  36. * Arduino GND <-> GND
  37. * SEN54 (1, white) VCC <-> 5V
  38. * SEN54 (2, blue) GND <-> GND
  39. * SEN54 (5, black) SEL <-> GND
  40. * Adafruit Mini GPS VIN <-> 5V
  41. * Adadruit Mini GPS GND <-> GND
  42. * Adafruit Power Boost 500 5V <-> 5V
  43. * Adafruit Power Boost 500 GND <-> GND
  44. * Adafruit Power Boost 500 LBO <-> 5 Arduino //DOES NOT REALLY WORK CHECK WIRING AND FUNCTIONALITY
  45. * Adafruit RGB ON/OFF Switch C+ <-> 5V
  46. * Adafruit RGB ON/OFF Switch C <-> GND
  47. * Adafruit RGB ON/OFF Switch R <-> 6 Arduino
  48. * Adafruit RGB ON/OFF Switch G <-> 7 Arduino
  49. * Adafruit RGB ON/OFF Switch B <-> 8 Arduino
  50. * Adafruit RGB ON/OFF Switch NC <-> EN Adafruit Power Boost 500
  51. *
  52. * Wiring Button (Colors)
  53. * R = Orange
  54. * G = Grey
  55. * B = Violett
  56. * C+ = White
  57. * C = Blue
  58. * NC = Yellow
  59. * NO (Center) = Green
  60. * Wiring 22mm Button
  61. * 1 -> EN
  62. * 2 -> GND
  63. *
  64. */
  65. #include <MKRNB.h>
  66. #include <TinyGPS++.h>
  67. #include <SparkFun_I2C_GPS_Arduino_Library.h>
  68. #include <RGBLed.h>
  69. #include <Arduino.h>
  70. #include <SensirionI2CSen5x.h>
  71. #include <Wire.h>
  72. // The used commands use up to 48 bytes. On some Arduino's the default buffer
  73. // space is not large enough
  74. #define MAXBUF_REQUIREMENT 48
  75. #if (defined(I2C_BUFFER_LENGTH) && (I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || (defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT)
  76. #define USE_PRODUCT_INFO
  77. #endif
  78. #define rLEDPIN 6 // Pin for red Button LED
  79. #define gLEDPIN 7 // Pin for green Button LED
  80. #define bLEDPIN 8 // Pin for blue Button LED
  81. #define batPin 5 // Pin to detect if battery gets low
  82. RGBLed ledButton(rLEDPIN, gLEDPIN, bLEDPIN, RGBLed::COMMON_ANODE);
  83. byte curR = 0;
  84. byte curG = 0;
  85. byte curB = 0;
  86. SensirionI2CSen5x sen5x;
  87. // The TinyGPS++ object
  88. I2CGPS myI2CGPS; //Hook object to the library
  89. TinyGPSPlus gps;
  90. boolean encodeGPSAgain = false;
  91. //Connection to DATAhub
  92. //NBClient client(false);
  93. //Otherwise the NBClient.connect() method waits until the internet connection gets ready, if you explicitly prohibit this it will wait forever.
  94. NBClient client(false);
  95. GPRS gprs;
  96. NB nbAccess;
  97. boolean connected = false;
  98. //Forwarder address for non SSL: http://forwarder.aml.media.tuwien.ac.at:11313/receive-reading/{token}
  99. // URL, path and port (for example: example.org
  100. // URL DATAHUB = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI0LCJpYXQiOjE3NDY3MDgxOTJ9.pKcHaTF88j6usI55lnWdgdXk9PESK4mGbKn6nf9Vv7A";
  101. char server[] = "aml.media.tuwien.ac.at";
  102. //char server[] = "forwarder.aml.media.tuwien.ac.at";
  103. // IMPORTANT: Place correct source Token here: THIS IS POCOBO 2 - 3
  104. char path[] = "/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI0LCJpYXQiOjE3NDY3MDgxOTJ9.pKcHaTF88j6usI55lnWdgdXk9PESK4mGbKn6nf9Vv7A";
  105. int port = 11312; // port 80 is the default for HTTP
  106. //Measured Data
  107. float lastPM1 = 0;
  108. float lastPM25 = 0;
  109. float lastPM4 = 0;
  110. float lastPM10 = 0;
  111. float lastHumidity = 0;
  112. float lastTemperature = 0;
  113. float lastVocIndex = 0;
  114. float lastNoxIndex = 0;
  115. //Timing
  116. unsigned long currentMillis = 0;
  117. uint32_t printTimer = millis(); //Just a timer for printing out values
  118. unsigned long sendToDATAhubInterval = 20000; //20sek; Interval for sending data to webservice = Data sampling interval
  119. unsigned long lastSendToDATAhub = 0;
  120. //String URL = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE0LCJpYXQiOjE2MDA4NDY0MDR9.0BPUK7NVTlqi7i9QFx9kcVY55jsn0qskPWDL1PKyKec";
  121. // Sensor Status
  122. // used for the LED
  123. // 0 = Startup
  124. // 1 = Sensor Running / Everything is fine
  125. // 2 = Measuring Data (Optional)
  126. // 3 = No GPS
  127. // 4 = No cell network
  128. // 5 = Battery Low
  129. // 6 = Sensor Error
  130. // 7 = Testoutput
  131. byte statusInfo = 0;
  132. //int sendcount = 0;
  133. /********************************************* SETUP *********************************************************/
  134. void setup() {
  135. updateLED(statusInfo);
  136. pinMode(batPin, INPUT_PULLUP);
  137. Serial.begin(115200);
  138. Serial1.begin(9600);
  139. //sendcount = 0;
  140. //while(!Serial); // UNCOMMENT(remove)
  141. // CONNECT Cell network
  142. //Serial.println("Starting connection to NB-IOT Service (A1)");
  143. // connection state
  144. //updateLED(4);
  145. connected = false;
  146. // After starting the modem with NB.begin()
  147. // attach to the GPRS network with the APN, login and password
  148. connectToNetwork();
  149. updateLED(statusInfo);
  150. Wire.begin();
  151. //Connect GPS to I2C
  152. //updateLED(3);
  153. if (myI2CGPS.begin() == false) {
  154. //Serial.println("GPS Module failed to respond. Please check wiring.");
  155. statusInfo = 3;
  156. updateLED(statusInfo);
  157. while (1)
  158. ; //Freeze!
  159. }
  160. encodeGPS();
  161. updateLED(statusInfo);
  162. // Init SEN54
  163. //updateLED(6);
  164. sen5x.begin(Wire);
  165. uint16_t error;
  166. char errorMessage[256];
  167. error = sen5x.deviceReset();
  168. if (error) {
  169. //Serial.print("Error trying to execute deviceReset(): ");
  170. errorToString(error, errorMessage, 256);
  171. //Serial.println(errorMessage);
  172. statusInfo = 6;
  173. updateLED(statusInfo);
  174. }
  175. // set a temperature offset in degrees celsius
  176. // Note: supported by SEN54 and SEN55 sensors
  177. // By default, the temperature and humidity outputs from the sensor
  178. // are compensated for the modules self-heating. If the module is
  179. // designed into a device, the temperature compensation might need
  180. // to be adapted to incorporate the change in thermal coupling and
  181. // self-heating of other device components.
  182. //
  183. // A guide to achieve optimal performance, including references
  184. // to mechanical design-in examples can be found in the app note
  185. // “SEN5x – Temperature Compensation Instruction” at www.sensirion.com.
  186. // Please refer to those application notes for further information
  187. // on the advanced compensation settings used
  188. // in `setTemperatureOffsetParameters`, `setWarmStartParameter` and
  189. // `setRhtAccelerationMode`.
  190. //
  191. // Adjust tempOffset to account for additional temperature offsets
  192. // exceeding the SEN module's self heating.
  193. float tempOffset = 0.0;
  194. error = sen5x.setTemperatureOffsetSimple(tempOffset);
  195. if (error) {
  196. //Serial.print("Error trying to execute setTemperatureOffsetSimple(): ");
  197. errorToString(error, errorMessage, 256);
  198. //Serial.println(errorMessage);
  199. statusInfo = 6;
  200. updateLED(statusInfo);
  201. } else {
  202. //Serial.print("Temperature Offset set to ");
  203. //Serial.print(tempOffset);
  204. //Serial.println(" deg. Celsius (SEN54/SEN55 only");
  205. }
  206. //Do an initial reading
  207. readSEN();
  208. updateLED(statusInfo);
  209. if (statusInfo == 0) statusInfo = 1; //Init finished without error. Statusinfo is still 0
  210. updateLED(statusInfo);
  211. }
  212. /********************************************* LOOP *********************************************************/
  213. void loop() {
  214. //updateLED(7);
  215. //Sending to DATAhub
  216. currentMillis = millis();
  217. if ((currentMillis - lastSendToDATAhub >= sendToDATAhubInterval)) {
  218. lastSendToDATAhub = currentMillis;
  219. updateLED(2);
  220. Serial.println("start sending");
  221. //TODO: Do this in a certain time interval
  222. //Serial.println("Start checking battery!");
  223. //checkBattery(); //does not really work ???
  224. //Encode GPS
  225. //Serial.println("Start encoding gps!");
  226. encodeGPS();
  227. //Read Sensor Data
  228. //INFO: Perhaps better to put in a timed interval; Also see sds.setCustomWorkingPeriod
  229. //Serial.println("Start reading sensor data!");
  230. readSEN();
  231. //Serial.println("After Sensor read; before DELAY");
  232. delay(1000);
  233. //Sending data to DATAhub Webservice
  234. //Serial.print("Start sending to DATAhub. statusInfo: ");
  235. //Serial.println(statusInfo);
  236. /*if (!gps.location.isUpdated()) {
  237. Serial.println("ERROR: GPS data not updated (no new signal)");
  238. statusInfo = 3;
  239. updateLED(statusInfo);
  240. }*/
  241. int satNum = gps.satellites.value();
  242. Serial.println("Satellites: " + String(satNum));
  243. //encodeGPS(); //Encode again
  244. if (statusInfo != 3 && statusInfo != 4 && statusInfo != 6) { //no gps, mobile connection and sensor error -> send
  245. sendToDATAhub();
  246. }
  247. //sendToDATAhub();
  248. updateLED(statusInfo);
  249. }
  250. }
  251. /********************************************* sendToDATAhub *********************************************************/
  252. void sendToDATAhub() {
  253. //Serial.println("connecting to DATAhub...");
  254. //Serial.println("Getting geo json datastring");
  255. String dataString = getGeoJSONDataString();
  256. //Serial.println("GOT Geo json datastring");
  257. unsigned int len = dataString.length() + 1;
  258. char data[len];
  259. dataString.toCharArray(data, len);
  260. //Serial.println("Transformed geo json data string to char array.");
  261. Serial.println("Server: " + String(server) + " Port: " + String(port));
  262. // if you get a connection, report back via serial:
  263. if (client.connect(server, port)) {
  264. Serial.println("connected to server -> YAY I CAME ACROSS THE CONNECTION PART!");
  265. //if (statusInfo != 3 && statusInfo != 4 && statusInfo != 6) {
  266. // Make a HTTP request:
  267. client.print("POST ");
  268. client.print(path);
  269. client.println(" HTTP/1.1");
  270. client.print("Host: ");
  271. client.println(server);
  272. client.println("Content-Type: text/plain");
  273. client.print("Content-Length: ");
  274. client.println(strlen(data));
  275. client.println();
  276. client.println(data);
  277. client.println("Connection: close");
  278. client.println();
  279. //}
  280. Serial.println("...sent to DATAhub!");
  281. if(statusInfo ==2) statusInfo = 1;
  282. } else {
  283. // if you didn't get a connection to the server:
  284. Serial.println("sendToDATAhub: connection failed");
  285. statusInfo = 4;
  286. updateLED(statusInfo);
  287. connected = false;
  288. Serial.println("Shutting down the modem");
  289. nbAccess.shutdown(); //restart the modem
  290. delay(5000);
  291. connectToNetwork();
  292. }
  293. }
  294. void connectToNetwork() {
  295. // After starting the modem with NB.begin()
  296. // attach to the GPRS network with the APN, login and password
  297. //&& (gprs.attachGPRS() == GPRS_READY)
  298. while (!connected) {
  299. Serial.println("Connecting to network!");
  300. if ((nbAccess.begin() == NB_READY)) {
  301. Serial.println("Connected to NB-IOT Service (A1)");
  302. connected = true;
  303. if(statusInfo ==2) statusInfo = 1;
  304. } else {
  305. Serial.println("Not connected to NB-IOT Service (A1)");
  306. delay(1000);
  307. statusInfo = 4;
  308. updateLED(statusInfo);
  309. }
  310. }
  311. }
  312. /********************************************* encodeGPS *********************************************************/
  313. void encodeGPS() {
  314. unsigned long start = millis();
  315. // For one second we parse GPS data and report some key values
  316. for (start; millis() - start < 1000;) {
  317. while (myI2CGPS.available()) { //available() returns the number of new bytes available from the GPS module
  318. gps.encode(myI2CGPS.read()); //Feed the GPS parser
  319. }
  320. }
  321. //Debugging
  322. //if we haven't seen lots of data in 5 seconds, something's wrong.
  323. if (start > 5000 && gps.charsProcessed() < 10) {
  324. //Serial.println("ERROR: Not getting any GPS data! Encoding again");
  325. statusInfo = 3;
  326. updateLED(statusInfo);
  327. encodeGPS(); //Encode again
  328. } else if (!gps.location.isValid()) { //also add timer for circumstances when there is definately no signal to find
  329. Serial.println("ERROR: GPS Data not valid! Encoding again");
  330. statusInfo = 3;
  331. updateLED(statusInfo);
  332. encodeGPS(); //Encode again
  333. } else if (gps.satellites.value() < 3) {
  334. Serial.println("ERROR: Not enough GPS satellites");
  335. statusInfo = 3;
  336. updateLED(statusInfo);
  337. //encodeGPS(); //Encode again
  338. } else {
  339. if(statusInfo ==2) statusInfo = 1; //no error occured
  340. }
  341. //printGPSData();
  342. }
  343. /********************************************* PrintGPSDATA *********************************************************/
  344. void printGPSData() {
  345. //We have new GPS data to deal with!
  346. Serial.println();
  347. if (gps.time.isValid()) {
  348. Serial.print(F("Date: "));
  349. Serial.print(gps.date.month());
  350. Serial.print(F("/"));
  351. Serial.print(gps.date.day());
  352. Serial.print(F("/"));
  353. Serial.print(gps.date.year());
  354. Serial.print((" Time: "));
  355. if (gps.time.hour() < 10) Serial.print(F("0"));
  356. Serial.print(gps.time.hour());
  357. Serial.print(F(":"));
  358. if (gps.time.minute() < 10) Serial.print(F("0"));
  359. Serial.print(gps.time.minute());
  360. Serial.print(F(":"));
  361. if (gps.time.second() < 10) Serial.print(F("0"));
  362. Serial.print(gps.time.second());
  363. Serial.println(); //Done printing time
  364. } else {
  365. Serial.println(F("Time not yet valid"));
  366. }
  367. if (gps.location.isValid()) {
  368. Serial.print("Location: ");
  369. Serial.print(gps.location.lat(), 6);
  370. Serial.print(F(", "));
  371. Serial.print(gps.location.lng(), 6);
  372. Serial.println();
  373. } else {
  374. Serial.println(F("Location not yet valid"));
  375. }
  376. }
  377. /********************************************* readSEN *********************************************************/
  378. void readSEN() {
  379. // Start Measurement //TODO: Remove from setup()?
  380. uint16_t error;
  381. char errorMessage[256];
  382. error = sen5x.startMeasurement();
  383. if (error) {
  384. //Serial.print("Error trying to execute startMeasurement(): ");
  385. errorToString(error, errorMessage, 256);
  386. //Serial.println(errorMessage);
  387. statusInfo = 6;
  388. updateLED(statusInfo);
  389. }
  390. error = sen5x.readMeasuredValues(
  391. lastPM1, lastPM25, lastPM4,
  392. lastPM10, lastHumidity, lastTemperature, lastVocIndex,
  393. lastNoxIndex);
  394. if (error) {
  395. //Serial.print("Error trying to execute readMeasuredValues(): ");
  396. errorToString(error, errorMessage, 256);
  397. //Serial.println(errorMessage);
  398. statusInfo = 6;
  399. updateLED(statusInfo);
  400. } else {
  401. //printSen54Data();
  402. if(statusInfo ==2) statusInfo = 1;
  403. }
  404. //status = 7;
  405. delay(1000);
  406. //updateLED(statusInfo);
  407. }
  408. /********************************************* printSEN54DATA *********************************************************/
  409. void printSen54Data() {
  410. Serial.print("PM 1.0: ");
  411. Serial.print(lastPM1);
  412. Serial.print("\t");
  413. Serial.print("PM 2.5: ");
  414. Serial.print(lastPM25);
  415. Serial.print("\t");
  416. Serial.print("PM 4.0: ");
  417. Serial.print(lastPM4);
  418. Serial.print("\t");
  419. Serial.print("PM 10.0: ");
  420. Serial.print(lastPM10);
  421. Serial.print("\t");
  422. Serial.print("Humidity: ");
  423. if (isnan(lastHumidity)) {
  424. Serial.print("n/a");
  425. } else {
  426. Serial.print(lastHumidity);
  427. }
  428. Serial.print("\t");
  429. Serial.print("Temperature: ");
  430. if (isnan(lastTemperature)) {
  431. Serial.print("n/a");
  432. } else {
  433. Serial.print(lastTemperature);
  434. }
  435. Serial.print("\t");
  436. Serial.print("VocIndex: ");
  437. if (isnan(lastVocIndex)) {
  438. Serial.print("n/a");
  439. } else {
  440. Serial.print(lastVocIndex);
  441. }
  442. Serial.print("\t");
  443. Serial.print("NoxIndex: ");
  444. if (isnan(lastNoxIndex)) {
  445. Serial.println("n/a");
  446. } else {
  447. Serial.println(lastNoxIndex);
  448. }
  449. }
  450. /********************************************* getGEOJSONDataString *********************************************************/
  451. String getGeoJSONDataString() {
  452. /* GeoJSON should look like this:
  453. {
  454. "type": "Feature",
  455. "geometry": {
  456. "type": "Point",
  457. "coordinates": [100.0, 0.0]
  458. },
  459. "properties": {
  460. "PM 1": [5.5, "myg/m3"],
  461. "PM 2.5": [43.5, "myg/m3"],
  462. "PM 4": [10.5, "myg/m3"],
  463. "PM 10": [21.5, "myg/m3"],
  464. "Humidity": [70, "%"],
  465. "Temperature": [23,5, "°C"],
  466. "VOC": [102, "VOC Index"],
  467. "timestamp": "123456723495",
  468. }
  469. }
  470. */
  471. /*
  472. String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":["+ String(gps.location.lat()) + "," + String(gps.location.lng()) + "]}, \"properties\": {\"PM 1\":[" + String(lastPM1) + ", \"myg/m3\"], \"PM 2.5\":[" + String(lastPM25) + ", \"myg/m3\"], \"PM 4\":[" + String(lastPM4) + ", \"myg/m3\"], \"PM 10\":[" + String(lastPM10) + ", \"myg/m3\"], \"Humidity\":[" +
  473. String(lastHumidity) + ", \"%\"], \"Temperature\":[" + String(lastTemperature) + ", \"°C\"], \"VOC\":[" + String(lastVocIndex) + ", \"VOC Index"], \"timestamp\":\"""\"}}";
  474. */
  475. String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":[" + String(gps.location.lng(), 6) + "," + String(gps.location.lat(), 6) + "]}, \"properties\": {\"PM 1\":[" + String(lastPM1) + ", \"myg/m3\"], \"PM 2.5\":[" + String(lastPM25) + ", \"myg/m3\"], \"PM 4\":[" + String(lastPM4) + ", \"myg/m3\"], \"PM 10\":[" + String(lastPM10) + ", \"myg/m3\"], \"Humidity\":[" + String(lastHumidity) + ", \"%\"], \"Temperature\":[" + String(lastTemperature) + ", \"°C\"], \"VOC\":[" + String(lastVocIndex) + ", \"VOC Index\"], \"timestamp\":\"""\"}}";
  476. //TODO: print this out!
  477. //Serial.println(json);
  478. //Serial.println("GeoJSON Datastring built");
  479. return json;
  480. }
  481. /********************************************* GetGeoJSONTestString *********************************************************/
  482. String getGeoJSONTestString() {
  483. /* GeoJSON should look like this:
  484. {
  485. "type": "Feature",
  486. "geometry": {
  487. "type": "Point",
  488. "coordinates": [100.0, 0.0]
  489. },
  490. "properties": {
  491. "Temperature": [24.5, "°C"],
  492. "Noise": [100.0, "dB"],
  493. "timestamp": "123456723495",
  494. }
  495. }
  496. */
  497. //String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":[16.791124, 47.865672]}, \"properties\": {\"Temperature\":[35, \"°C\"], \"Noise\":[130, \"dB\"], \"timestamp\":\"\"}}";
  498. String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":[16.504511, 48.225247]}, \"properties\": {\"PM 1\":[" + String(lastPM1) + ", \"myg/m3\"], \"PM 2.5\":[" + String(lastPM25) + ", \"myg/m3\"], \"PM 4\":[" + String(lastPM4) + ", \"myg/m3\"], \"PM 10\":[" + String(lastPM10) + ", \"myg/m3\"], \"Humidity\":[" + String(lastHumidity) + ", \"%\"], \"Temperature\":[" + String(lastTemperature) + ", \"°C\"], \"VOC\":[" + String(lastVocIndex) + ", \"VOC Index\"], \"timestamp\":\""
  499. "\"}}";
  500. return json;
  501. }
  502. /********************************************* checkBattery *********************************************************/
  503. void checkBattery() {
  504. //DOES NOT WORK: LOW LED on the Powerboost is active but batPin reading is 1
  505. // reads the pin connect to the LBO output of the powerboost 500 Unit
  506. int batState = digitalRead(batPin);
  507. if (batState == LOW) {
  508. //Sets the LED to red if battery is low
  509. statusInfo = 5;
  510. updateLED(statusInfo);
  511. }
  512. //Serial.println("Battery state: " + batState);
  513. }
  514. /********************************************* updateLED *********************************************************/
  515. void updateLED(byte status) {
  516. //Status and LED Colours:
  517. //0 = While Setup/Startup: YELLOW (255, 225, 0)
  518. //1 = Running & Everything is OK: GREEN (0, 255, 0)
  519. //2 = Measuring DATA: GREEN (200, 255, 50)
  520. //3 = NO GPS Signal/Position/Fix: BLUE (0, 0, 255)
  521. //4 = NO Cell Network/Connection: PINK (255, 0, 255)
  522. //5 = Batterry low: RED (255, 0, 0)
  523. //6 = Sensor Error: VIOLETT (170, 0, 255)
  524. //7 = TESTOUTPUT GREEN/PETROL (3, 252, 177)
  525. statusInfo = status;
  526. if (status == 0) {
  527. ledButton.crossFade(curR, curG, curB, 255, 255, 0, 10, 500);
  528. curR = 255;
  529. curG = 255;
  530. curB = 0;
  531. } else if (status == 1) {
  532. ledButton.crossFade(curR, curG, curB, 0, 255, 0, 10, 500);
  533. curR = 0;
  534. curG = 255;
  535. curB = 0;
  536. //} else if (status == 2) { ledButton.flash(200, 255, 50, 50);
  537. } else if (status == 2) {
  538. ledButton.crossFade(curR, curG, curB, 200, 255, 50, 10, 500);
  539. //ledButton.flash(200, 255, 50, 1000);
  540. curR = 200;
  541. curG = 255;
  542. curB = 50;
  543. } else if (status == 3) {
  544. ledButton.crossFade(curR, curG, curB, 0, 0, 255, 10, 500);
  545. curR = 0;
  546. curG = 0;
  547. curB = 255;
  548. } else if (status == 4) {
  549. ledButton.crossFade(curR, curG, curB, 255, 0, 255, 10, 500);
  550. curR = 255;
  551. curG = 0;
  552. curB = 255;
  553. } else if (status == 5) {
  554. ledButton.crossFade(curR, curG, curB, 255, 0, 0, 10, 500);
  555. curR = 255;
  556. curG = 0;
  557. curB = 0;
  558. } else if (status == 6) {
  559. ledButton.crossFade(curR, curG, curB, 170, 0, 255, 10, 500);
  560. curR = 170;
  561. curG = 0;
  562. curB = 255;
  563. } else if (status == 7) {
  564. ledButton.crossFade(curR, curG, curB, 3, 252, 177, 10, 500);
  565. curR = 3;
  566. curG = 252;
  567. curB = 177; //Testoutput
  568. }
  569. statusInfo = status;
  570. }