Pocobo_2.ino 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /*Pocobo 2- Pollution Collecting Bottle 2
  2. *
  3. * v1.0
  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. * Challenges, Problems, Errors, etc.
  66. * - SOLVED: Standard SoftwareSerial Library does not work with SAMD Controllers. (Serial1 is now passing through)
  67. * - SOLVED: HTTP Post: https://forum.arduino.cc/t/mkr-nb-1500-http-post/680965
  68. * -> SIM-Card does not support NB-IoT: https://www.a1.net/nb-iot
  69. * -> Sending SMS works, but no GPRS connection via NB-IoT.
  70. * - SOLVED: GPS needs 3minutes to get a fix. (Using TinyGPS++ Library)
  71. * - SOLVED: Arduino does not work with battery (Use Power Boost 500 Module)
  72. * - SOLVED: Button LED is not lighting correct if system runs on battery (arduino not connect to Power via USB).
  73. * -> it's color is white ??? WHY; Turns green if arduino is connected to USB
  74. * -> Moved activation of Button to the top of setup()
  75. -> see aml_pocobo2_testledbutton.ino
  76. * - OPEN: LED stays green for a long time if sensor is inside (NO GPS).
  77. * - OPEN: Indicating low battery level by use of LBO pin
  78. * -> https://forums.adafruit.com/viewtopic.php?f=19&p=757864
  79. -> How to use the LB Pin on the Power boost?
  80. -> https://forums.adafruit.com/viewtopic.php?f=19&t=58281
  81. -> https://forums.adafruit.com/viewtopic.php?f=19&t=80260
  82. -> https://forums.adafruit.com/viewtopic.php?p=379644
  83. -> https://forum.arduino.cc/t/adafruit-powerboost-500c-arduino-micro-lbo/251123
  84. -> https://electronics.stackexchange.com/questions/334472/general-electrical-question-with-regards-to-the-lbo-pin-on-the-adafruit-boost-5
  85. * - SOlVED: After switching OFF and ON again, the SEN54 delivers nan results
  86. * -> works after uploading the code, but not after switching OFF and ON again with the button.
  87. * - SOLVED: LED Works correctly with battery if Arduino is powered via VCC
  88. -> This should not be correct, as this is the 3.3v Power I/O
  89. -> Check wiring
  90. = Works also via VIN 9.1.24
  91. * - TODO: Send status messages to the Datahub.
  92. * - TODO: Get Battery status
  93. * - SOLVED: Device restarts every 20 secs (sampling interval)
  94. - Battery is charged
  95. - LED is connected to the LBO
  96. * - SOLVED: GPS sends only two decimals
  97. - https://forum.arduino.cc/t/tinygpsplus-gives-out-the-location-only-up-to-two-decimals/601442
  98. - String function seems to cut decimals: String(double) https://forum.arduino.cc/t/string-function-seems-to-be-rounding-doubles/642177
  99. - include numer of decimals (6) when casting to String.
  100. * - BUG: After putting sensor inside (no gps, LED green) and then outside again pocobo does not send data to server. gets stuck
  101. - does not get accross this line in sendtodatahub: if (client.connect(server, port))
  102. * TODO: If an error occurs update the led immediately. (and make sure it is not overridden);
  103. *
  104. *
  105. *
  106. *
  107. *
  108. *
  109. * SOURCE TOKENS:
  110. * POCOBO 2 - 0: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE5LCJpYXQiOjE2Mzc5MzIzMjF9.fGMMPIMp-yHKX7yqddMKU3ItpcwiGD4srkY1-vj0Pz4
  111. POCOBO 2 - 1: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIxLCJpYXQiOjE3MTIwNjc4NTZ9._YmIoqeE98XWNu629MFS1OOGGzWxPnKH-zI06zFWOnI
  112. POCOBO 2 - 2: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzLCJpYXQiOjE3NDUzMTgxOTJ9.n2c2huqnC5p4MRaBf-NksLlNKcW976t1mwZMOPhiBa4
  113. Pocobo 2 - 3: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI0LCJpYXQiOjE3NDY3MDgxOTJ9.pKcHaTF88j6usI55lnWdgdXk9PESK4mGbKn6nf9Vv7A
  114. Pocobo 2 - 4: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI1LCJpYXQiOjE3NDY3MDgyNzF9.UzfhKlXXXO8uFUsBgvVkLg19dRZBHP5rjXvncYZ2JeA
  115. *
  116. */
  117. #include <MKRNB.h>
  118. #include <TinyGPS++.h>
  119. #include <SparkFun_I2C_GPS_Arduino_Library.h>
  120. #include <RGBLed.h>
  121. #include <Arduino.h>
  122. #include <SensirionI2CSen5x.h>
  123. #include <Wire.h>
  124. // The used commands use up to 48 bytes. On some Arduino's the default buffer
  125. // space is not large enough
  126. #define MAXBUF_REQUIREMENT 48
  127. #if (defined(I2C_BUFFER_LENGTH) && (I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || (defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT)
  128. #define USE_PRODUCT_INFO
  129. #endif
  130. #define rLEDPIN 6 // Pin for red Button LED
  131. #define gLEDPIN 7 // Pin for green Button LED
  132. #define bLEDPIN 8 // Pin for blue Button LED
  133. #define batPin 5 // Pin to detect if battery gets low
  134. RGBLed ledButton(rLEDPIN, gLEDPIN, bLEDPIN, RGBLed::COMMON_ANODE);
  135. byte curR = 0;
  136. byte curG = 0;
  137. byte curB = 0;
  138. SensirionI2CSen5x sen5x;
  139. // The TinyGPS++ object
  140. I2CGPS myI2CGPS; //Hook object to the library
  141. TinyGPSPlus gps;
  142. boolean encodeGPSAgain = false;
  143. //Connection to DATAhub
  144. //NBClient client(false);
  145. //Otherwise the NBClient.connect() method waits until the internet connection gets ready, if you explicitly prohibit this it will wait forever.
  146. NBClient client(false);
  147. GPRS gprs;
  148. NB nbAccess;
  149. boolean connected = false;
  150. //Forwarder address for non SSL: http://forwarder.aml.media.tuwien.ac.at:11313/receive-reading/{token}
  151. // URL, path and port (for example: example.org
  152. // URL DATAHUB = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI0LCJpYXQiOjE3NDY3MDgxOTJ9.pKcHaTF88j6usI55lnWdgdXk9PESK4mGbKn6nf9Vv7A";
  153. char server[] = "aml.media.tuwien.ac.at";
  154. //char server[] = "forwarder.aml.media.tuwien.ac.at";
  155. // IMPORTANT: Place correct source Token here: THIS IS POCOBO 2 - 3
  156. char path[] = "/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI0LCJpYXQiOjE3NDY3MDgxOTJ9.pKcHaTF88j6usI55lnWdgdXk9PESK4mGbKn6nf9Vv7A";
  157. int port = 11312; // port 80 is the default for HTTP
  158. //Measured Data
  159. float lastPM1 = 0;
  160. float lastPM25 = 0;
  161. float lastPM4 = 0;
  162. float lastPM10 = 0;
  163. float lastHumidity = 0;
  164. float lastTemperature = 0;
  165. float lastVocIndex = 0;
  166. float lastNoxIndex = 0;
  167. //Timing
  168. unsigned long currentMillis = 0;
  169. uint32_t printTimer = millis(); //Just a timer for printing out values
  170. unsigned long sendToDATAhubInterval = 20000; //20sek; Interval for sending data to webservice = Data sampling interval
  171. unsigned long lastSendToDATAhub = 0;
  172. //String URL = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE0LCJpYXQiOjE2MDA4NDY0MDR9.0BPUK7NVTlqi7i9QFx9kcVY55jsn0qskPWDL1PKyKec";
  173. // Sensor Status
  174. // used for the LED
  175. // 0 = Startup
  176. // 1 = Sensor Running / Everything is fine
  177. // 2 = Measuring Data (Optional)
  178. // 3 = No GPS
  179. // 4 = No cell network
  180. // 5 = Battery Low
  181. // 6 = Sensor Error
  182. // 7 = Testoutput
  183. byte statusInfo = 0;
  184. //int sendcount = 0;
  185. /********************************************* SETUP *********************************************************/
  186. void setup() {
  187. updateLED(statusInfo);
  188. pinMode(batPin, INPUT_PULLUP);
  189. Serial.begin(115200);
  190. Serial1.begin(9600);
  191. //sendcount = 0;
  192. //while(!Serial); // UNCOMMENT(remove)
  193. // CONNECT Cell network
  194. //Serial.println("Starting connection to NB-IOT Service (A1)");
  195. // connection state
  196. //updateLED(4);
  197. connected = false;
  198. // After starting the modem with NB.begin()
  199. // attach to the GPRS network with the APN, login and password
  200. connectToNetwork();
  201. updateLED(statusInfo);
  202. Wire.begin();
  203. //Connect GPS to I2C
  204. //updateLED(3);
  205. if (myI2CGPS.begin() == false) {
  206. //Serial.println("GPS Module failed to respond. Please check wiring.");
  207. statusInfo = 3;
  208. updateLED(statusInfo);
  209. while (1)
  210. ; //Freeze!
  211. }
  212. encodeGPS();
  213. updateLED(statusInfo);
  214. // Init SEN54
  215. //updateLED(6);
  216. sen5x.begin(Wire);
  217. uint16_t error;
  218. char errorMessage[256];
  219. error = sen5x.deviceReset();
  220. if (error) {
  221. //Serial.print("Error trying to execute deviceReset(): ");
  222. errorToString(error, errorMessage, 256);
  223. //Serial.println(errorMessage);
  224. statusInfo = 6;
  225. updateLED(statusInfo);
  226. }
  227. // set a temperature offset in degrees celsius
  228. // Note: supported by SEN54 and SEN55 sensors
  229. // By default, the temperature and humidity outputs from the sensor
  230. // are compensated for the modules self-heating. If the module is
  231. // designed into a device, the temperature compensation might need
  232. // to be adapted to incorporate the change in thermal coupling and
  233. // self-heating of other device components.
  234. //
  235. // A guide to achieve optimal performance, including references
  236. // to mechanical design-in examples can be found in the app note
  237. // “SEN5x – Temperature Compensation Instruction” at www.sensirion.com.
  238. // Please refer to those application notes for further information
  239. // on the advanced compensation settings used
  240. // in `setTemperatureOffsetParameters`, `setWarmStartParameter` and
  241. // `setRhtAccelerationMode`.
  242. //
  243. // Adjust tempOffset to account for additional temperature offsets
  244. // exceeding the SEN module's self heating.
  245. float tempOffset = 0.0;
  246. error = sen5x.setTemperatureOffsetSimple(tempOffset);
  247. if (error) {
  248. //Serial.print("Error trying to execute setTemperatureOffsetSimple(): ");
  249. errorToString(error, errorMessage, 256);
  250. //Serial.println(errorMessage);
  251. statusInfo = 6;
  252. updateLED(statusInfo);
  253. } else {
  254. //Serial.print("Temperature Offset set to ");
  255. //Serial.print(tempOffset);
  256. //Serial.println(" deg. Celsius (SEN54/SEN55 only");
  257. }
  258. //Do an initial reading
  259. readSEN();
  260. updateLED(statusInfo);
  261. if (statusInfo == 0) statusInfo = 1; //Init finished without error. Statusinfo is still 0
  262. updateLED(statusInfo);
  263. }
  264. /********************************************* LOOP *********************************************************/
  265. void loop() {
  266. //updateLED(7);
  267. //Sending to DATAhub
  268. currentMillis = millis();
  269. if ((currentMillis - lastSendToDATAhub >= sendToDATAhubInterval)) {
  270. lastSendToDATAhub = currentMillis;
  271. updateLED(2);
  272. Serial.println("start sending");
  273. //TODO: Do this in a certain time interval
  274. //Serial.println("Start checking battery!");
  275. //checkBattery(); //does not really work ???
  276. //Encode GPS
  277. //Serial.println("Start encoding gps!");
  278. encodeGPS();
  279. //Read Sensor Data
  280. //INFO: Perhaps better to put in a timed interval; Also see sds.setCustomWorkingPeriod
  281. //Serial.println("Start reading sensor data!");
  282. readSEN();
  283. //Serial.println("After Sensor read; before DELAY");
  284. delay(1000);
  285. //Sending data to DATAhub Webservice
  286. //Serial.print("Start sending to DATAhub. statusInfo: ");
  287. //Serial.println(statusInfo);
  288. /*if (!gps.location.isUpdated()) {
  289. Serial.println("ERROR: GPS data not updated (no new signal)");
  290. statusInfo = 3;
  291. updateLED(statusInfo);
  292. }*/
  293. int satNum = gps.satellites.value();
  294. Serial.println("Satellites: " + String(satNum));
  295. //encodeGPS(); //Encode again
  296. if (statusInfo != 3 && statusInfo != 4 && statusInfo != 6) { //no gps, mobile connection and sensor error -> send
  297. sendToDATAhub();
  298. }
  299. //sendToDATAhub();
  300. updateLED(statusInfo);
  301. }
  302. }
  303. /********************************************* sendToDATAhub *********************************************************/
  304. void sendToDATAhub() {
  305. //Serial.println("connecting to DATAhub...");
  306. //Serial.println("Getting geo json datastring");
  307. String dataString = getGeoJSONDataString();
  308. //Serial.println("GOT Geo json datastring");
  309. unsigned int len = dataString.length() + 1;
  310. char data[len];
  311. dataString.toCharArray(data, len);
  312. //Serial.println("Transformed geo json data string to char array.");
  313. Serial.println("Server: " + String(server) + " Port: " + String(port));
  314. // if you get a connection, report back via serial:
  315. if (client.connect(server, port)) {
  316. Serial.println("connected to server -> YAY I CAME ACROSS THE CONNECTION PART!");
  317. //if (statusInfo != 3 && statusInfo != 4 && statusInfo != 6) {
  318. // Make a HTTP request:
  319. client.print("POST ");
  320. client.print(path);
  321. client.println(" HTTP/1.1");
  322. client.print("Host: ");
  323. client.println(server);
  324. client.println("Content-Type: text/plain");
  325. client.print("Content-Length: ");
  326. client.println(strlen(data));
  327. client.println();
  328. client.println(data);
  329. client.println("Connection: close");
  330. client.println();
  331. //}
  332. Serial.println("...sent to DATAhub!");
  333. if(statusInfo ==2) statusInfo = 1;
  334. } else {
  335. // if you didn't get a connection to the server:
  336. Serial.println("sendToDATAhub: connection failed");
  337. statusInfo = 4;
  338. updateLED(statusInfo);
  339. connected = false;
  340. Serial.println("Shutting down the modem");
  341. nbAccess.shutdown(); //restart the modem
  342. delay(5000);
  343. connectToNetwork();
  344. }
  345. }
  346. void connectToNetwork() {
  347. // After starting the modem with NB.begin()
  348. // attach to the GPRS network with the APN, login and password
  349. //&& (gprs.attachGPRS() == GPRS_READY)
  350. while (!connected) {
  351. Serial.println("Connecting to network!");
  352. if ((nbAccess.begin() == NB_READY)) {
  353. Serial.println("Connected to NB-IOT Service (A1)");
  354. connected = true;
  355. if(statusInfo ==2) statusInfo = 1;
  356. } else {
  357. Serial.println("Not connected to NB-IOT Service (A1)");
  358. delay(1000);
  359. statusInfo = 4;
  360. updateLED(statusInfo);
  361. }
  362. }
  363. }
  364. /********************************************* encodeGPS *********************************************************/
  365. void encodeGPS() {
  366. unsigned long start = millis();
  367. // For one second we parse GPS data and report some key values
  368. for (start; millis() - start < 1000;) {
  369. while (myI2CGPS.available()) { //available() returns the number of new bytes available from the GPS module
  370. gps.encode(myI2CGPS.read()); //Feed the GPS parser
  371. }
  372. }
  373. //Debugging
  374. //if we haven't seen lots of data in 5 seconds, something's wrong.
  375. if (start > 5000 && gps.charsProcessed() < 10) {
  376. //Serial.println("ERROR: Not getting any GPS data! Encoding again");
  377. statusInfo = 3;
  378. updateLED(statusInfo);
  379. encodeGPS(); //Encode again
  380. } else if (!gps.location.isValid()) { //also add timer for circumstances when there is definately no signal to find
  381. Serial.println("ERROR: GPS Data not valid! Encoding again");
  382. statusInfo = 3;
  383. updateLED(statusInfo);
  384. encodeGPS(); //Encode again
  385. } else if (gps.satellites.value() < 3) {
  386. Serial.println("ERROR: Not enough GPS satellites");
  387. statusInfo = 3;
  388. updateLED(statusInfo);
  389. //encodeGPS(); //Encode again
  390. } else {
  391. if(statusInfo ==2) statusInfo = 1; //no error occured
  392. }
  393. //printGPSData();
  394. }
  395. /********************************************* PrintGPSDATA *********************************************************/
  396. void printGPSData() {
  397. //We have new GPS data to deal with!
  398. Serial.println();
  399. if (gps.time.isValid()) {
  400. Serial.print(F("Date: "));
  401. Serial.print(gps.date.month());
  402. Serial.print(F("/"));
  403. Serial.print(gps.date.day());
  404. Serial.print(F("/"));
  405. Serial.print(gps.date.year());
  406. Serial.print((" Time: "));
  407. if (gps.time.hour() < 10) Serial.print(F("0"));
  408. Serial.print(gps.time.hour());
  409. Serial.print(F(":"));
  410. if (gps.time.minute() < 10) Serial.print(F("0"));
  411. Serial.print(gps.time.minute());
  412. Serial.print(F(":"));
  413. if (gps.time.second() < 10) Serial.print(F("0"));
  414. Serial.print(gps.time.second());
  415. Serial.println(); //Done printing time
  416. } else {
  417. Serial.println(F("Time not yet valid"));
  418. }
  419. if (gps.location.isValid()) {
  420. Serial.print("Location: ");
  421. Serial.print(gps.location.lat(), 6);
  422. Serial.print(F(", "));
  423. Serial.print(gps.location.lng(), 6);
  424. Serial.println();
  425. } else {
  426. Serial.println(F("Location not yet valid"));
  427. }
  428. }
  429. /********************************************* readSEN *********************************************************/
  430. void readSEN() {
  431. // Start Measurement //TODO: Remove from setup()?
  432. uint16_t error;
  433. char errorMessage[256];
  434. error = sen5x.startMeasurement();
  435. if (error) {
  436. //Serial.print("Error trying to execute startMeasurement(): ");
  437. errorToString(error, errorMessage, 256);
  438. //Serial.println(errorMessage);
  439. statusInfo = 6;
  440. updateLED(statusInfo);
  441. }
  442. error = sen5x.readMeasuredValues(
  443. lastPM1, lastPM25, lastPM4,
  444. lastPM10, lastHumidity, lastTemperature, lastVocIndex,
  445. lastNoxIndex);
  446. if (error) {
  447. //Serial.print("Error trying to execute readMeasuredValues(): ");
  448. errorToString(error, errorMessage, 256);
  449. //Serial.println(errorMessage);
  450. statusInfo = 6;
  451. updateLED(statusInfo);
  452. } else {
  453. //printSen54Data();
  454. if(statusInfo ==2) statusInfo = 1;
  455. }
  456. //status = 7;
  457. delay(1000);
  458. //updateLED(statusInfo);
  459. }
  460. /********************************************* printSEN54DATA *********************************************************/
  461. void printSen54Data() {
  462. Serial.print("PM 1.0: ");
  463. Serial.print(lastPM1);
  464. Serial.print("\t");
  465. Serial.print("PM 2.5: ");
  466. Serial.print(lastPM25);
  467. Serial.print("\t");
  468. Serial.print("PM 4.0: ");
  469. Serial.print(lastPM4);
  470. Serial.print("\t");
  471. Serial.print("PM 10.0: ");
  472. Serial.print(lastPM10);
  473. Serial.print("\t");
  474. Serial.print("Humidity: ");
  475. if (isnan(lastHumidity)) {
  476. Serial.print("n/a");
  477. } else {
  478. Serial.print(lastHumidity);
  479. }
  480. Serial.print("\t");
  481. Serial.print("Temperature: ");
  482. if (isnan(lastTemperature)) {
  483. Serial.print("n/a");
  484. } else {
  485. Serial.print(lastTemperature);
  486. }
  487. Serial.print("\t");
  488. Serial.print("VocIndex: ");
  489. if (isnan(lastVocIndex)) {
  490. Serial.print("n/a");
  491. } else {
  492. Serial.print(lastVocIndex);
  493. }
  494. Serial.print("\t");
  495. Serial.print("NoxIndex: ");
  496. if (isnan(lastNoxIndex)) {
  497. Serial.println("n/a");
  498. } else {
  499. Serial.println(lastNoxIndex);
  500. }
  501. }
  502. /********************************************* getGEOJSONDataString *********************************************************/
  503. String getGeoJSONDataString() {
  504. /* GeoJSON should look like this:
  505. {
  506. "type": "Feature",
  507. "geometry": {
  508. "type": "Point",
  509. "coordinates": [100.0, 0.0]
  510. },
  511. "properties": {
  512. "PM 1": [5.5, "myg/m3"],
  513. "PM 2.5": [43.5, "myg/m3"],
  514. "PM 4": [10.5, "myg/m3"],
  515. "PM 10": [21.5, "myg/m3"],
  516. "Humidity": [70, "%"],
  517. "Temperature": [23,5, "°C"],
  518. "VOC": [102, "VOC Index"],
  519. "timestamp": "123456723495",
  520. }
  521. }
  522. */
  523. /*
  524. 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\":[" +
  525. String(lastHumidity) + ", \"%\"], \"Temperature\":[" + String(lastTemperature) + ", \"°C\"], \"VOC\":[" + String(lastVocIndex) + ", \"VOC Index"], \"timestamp\":\"""\"}}";
  526. */
  527. 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\":\"""\"}}";
  528. //TODO: print this out!
  529. //Serial.println(json);
  530. //Serial.println("GeoJSON Datastring built");
  531. return json;
  532. }
  533. /********************************************* GetGeoJSONTestString *********************************************************/
  534. String getGeoJSONTestString() {
  535. /* GeoJSON should look like this:
  536. {
  537. "type": "Feature",
  538. "geometry": {
  539. "type": "Point",
  540. "coordinates": [100.0, 0.0]
  541. },
  542. "properties": {
  543. "Temperature": [24.5, "°C"],
  544. "Noise": [100.0, "dB"],
  545. "timestamp": "123456723495",
  546. }
  547. }
  548. */
  549. //String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":[16.791124, 47.865672]}, \"properties\": {\"Temperature\":[35, \"°C\"], \"Noise\":[130, \"dB\"], \"timestamp\":\"\"}}";
  550. 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\":\""
  551. "\"}}";
  552. return json;
  553. }
  554. /********************************************* checkBattery *********************************************************/
  555. void checkBattery() {
  556. //DOES NOT WORK: LOW LED on the Powerboost is active but batPin reading is 1
  557. // reads the pin connect to the LBO output of the powerboost 500 Unit
  558. int batState = digitalRead(batPin);
  559. if (batState == LOW) {
  560. //Sets the LED to red if battery is low
  561. statusInfo = 5;
  562. updateLED(statusInfo);
  563. }
  564. //Serial.println("Battery state: " + batState);
  565. }
  566. /********************************************* updateLED *********************************************************/
  567. void updateLED(byte status) {
  568. //Status and LED Colours:
  569. //0 = While Setup/Startup: YELLOW (255, 225, 0)
  570. //1 = Running & Everything is OK: GREEN (0, 255, 0)
  571. //2 = Measuring DATA: GREEN (200, 255, 50)
  572. //3 = NO GPS Signal/Position/Fix: BLUE (0, 0, 255)
  573. //4 = NO Cell Network/Connection: PINK (255, 0, 255)
  574. //5 = Batterry low: RED (255, 0, 0)
  575. //6 = Sensor Error: VIOLETT (170, 0, 255)
  576. //7 = TESTOUTPUT GREEN/PETROL (3, 252, 177)
  577. statusInfo = status;
  578. if (status == 0) {
  579. ledButton.crossFade(curR, curG, curB, 255, 255, 0, 10, 500);
  580. curR = 255;
  581. curG = 255;
  582. curB = 0;
  583. } else if (status == 1) {
  584. ledButton.crossFade(curR, curG, curB, 0, 255, 0, 10, 500);
  585. curR = 0;
  586. curG = 255;
  587. curB = 0;
  588. //} else if (status == 2) { ledButton.flash(200, 255, 50, 50);
  589. } else if (status == 2) {
  590. ledButton.crossFade(curR, curG, curB, 200, 255, 50, 10, 500);
  591. //ledButton.flash(200, 255, 50, 1000);
  592. curR = 200;
  593. curG = 255;
  594. curB = 50;
  595. } else if (status == 3) {
  596. ledButton.crossFade(curR, curG, curB, 0, 0, 255, 10, 500);
  597. curR = 0;
  598. curG = 0;
  599. curB = 255;
  600. } else if (status == 4) {
  601. ledButton.crossFade(curR, curG, curB, 255, 0, 255, 10, 500);
  602. curR = 255;
  603. curG = 0;
  604. curB = 255;
  605. } else if (status == 5) {
  606. ledButton.crossFade(curR, curG, curB, 255, 0, 0, 10, 500);
  607. curR = 255;
  608. curG = 0;
  609. curB = 0;
  610. } else if (status == 6) {
  611. ledButton.crossFade(curR, curG, curB, 170, 0, 255, 10, 500);
  612. curR = 170;
  613. curG = 0;
  614. curB = 255;
  615. } else if (status == 7) {
  616. ledButton.crossFade(curR, curG, curB, 3, 252, 177, 10, 500);
  617. curR = 3;
  618. curG = 252;
  619. curB = 177; //Testoutput
  620. }
  621. statusInfo = status;
  622. }