|
| 1 | +/* |
| 2 | + * The MySensors Arduino library handles the wireless radio link and protocol |
| 3 | + * between your home built sensors/actuators and HA controller of choice. |
| 4 | + * The sensors forms a self healing radio network with optional repeaters. Each |
| 5 | + * repeater and gateway builds a routing tables in EEPROM which keeps track of the |
| 6 | + * network topology allowing messages to be routed to nodes. |
| 7 | + * |
| 8 | + * Created by Henrik Ekblad < [email protected]> |
| 9 | + * Copyright (C) 2013-2015 Sensnology AB |
| 10 | + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors |
| 11 | + * |
| 12 | + * Documentation: http://www.mysensors.org |
| 13 | + * Support Forum: http://forum.mysensors.org |
| 14 | + * |
| 15 | + * This program is free software; you can redistribute it and/or |
| 16 | + * modify it under the terms of the GNU General Public License |
| 17 | + * version 2 as published by the Free Software Foundation. |
| 18 | + * |
| 19 | + ******************************* |
| 20 | + * |
| 21 | + * DESCRIPTION |
| 22 | + * |
| 23 | + * Plantower PMS-7003 fine dust sensor |
| 24 | + * |
| 25 | + * This sensor uses a frickin' laser to measure lots of different fine dust levels, between 0.3 and 10 microns. |
| 26 | + * It outputs in um/m3, or you can get access to the raw data of the particles it has counted. |
| 27 | + * |
| 28 | + * It needs 5v to operate, but communicates at 3.3 volt. It communicates with your board over serial at 9600 speed. |
| 29 | + * |
| 30 | + * |
| 31 | + * This code makes use of kindly shared code by Scapeler: |
| 32 | + * |
| 33 | + * - - - |
| 34 | + * Copyright 2017 Scapeler |
| 35 | + * |
| 36 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 37 | + * you may not use this file except in compliance with the License. |
| 38 | + * You may obtain a copy of the License at |
| 39 | + |
| 40 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 41 | + |
| 42 | + * Unless required by applicable law or agreed to in writing, software |
| 43 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 44 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 45 | + * See the License for the specific language governing permissions and |
| 46 | + * limitations under the License. |
| 47 | + * - - - |
| 48 | +*/ |
| 49 | + |
| 50 | +//------------------------------------------------------------------------------ |
| 51 | + |
| 52 | +// if you uncomment this, you can get test and debug updates about the sensor' wireless connection by using the serial monitor tool. |
| 53 | +#define MY_DEBUG |
| 54 | + |
| 55 | +// Enable and select radio type attached |
| 56 | +#define MY_RADIO_NRF24 // A 2.4Ghz transmitter and receiver, often used with MySensors. |
| 57 | +#define MY_RF24_PA_LEVEL RF24_PA_MIN // This sets a low-power mode for the radio. Useful if you use the verison with the bigger antenna, but don't want to power that from a separate power source. It can also fix problems with fake Chinese versions of the radio. |
| 58 | +// #define MY_RADIO_RFM69 // 433Mhz transmitter and reveiver. |
| 59 | + |
| 60 | +// Choose if you want this sensor to also be a repeater. |
| 61 | +// #define MY_REPEATER_FEATURE // Just remove the two slashes at the beginning of this line to also enable this sensor to act as a repeater for other sensors. If this node is on battery power, you probably shouldn't enable this. |
| 62 | + |
| 63 | +#include <SPI.h> |
| 64 | +#include <MySensors.h> |
| 65 | +#include <SoftwareSerial.h> |
| 66 | + |
| 67 | +#define CHILD_ID_DUST_PM10 0 |
| 68 | +#define CHILD_ID_DUST_PM25 1 |
| 69 | +#define CHILD_ID_DUST_PM100 2 |
| 70 | + |
| 71 | + |
| 72 | +// Mysensors settings. |
| 73 | +MyMessage msgDust10(CHILD_ID_DUST_PM10, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later. |
| 74 | +MyMessage msgDust10b(CHILD_ID_DUST_PM10, V_UNIT_PREFIX); |
| 75 | +MyMessage msgDust25(CHILD_ID_DUST_PM25, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later. |
| 76 | +MyMessage msgDust25b(CHILD_ID_DUST_PM25, V_UNIT_PREFIX); |
| 77 | +MyMessage msgDust100(CHILD_ID_DUST_PM100, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later. |
| 78 | +MyMessage msgDust100b(CHILD_ID_DUST_PM100, V_UNIT_PREFIX); |
| 79 | + |
| 80 | + |
| 81 | +// These defines and variables can be changed: |
| 82 | +int dustSlowDown = 20; // The dust sensor is internally checked approximately every 700 or 800 milliseconds. Once in how many loops should it send the data? |
| 83 | +unsigned long dustMeasurementInterval = 700; // This is a fickle thing. Changing it can give more time-outs. |
| 84 | +SoftwareSerial mySerial(10, 11); // RX, TX . You can choose other pins if you prefer. |
| 85 | + |
| 86 | + |
| 87 | +// PROBABLY BEST NOT TO CHANGE THESE VARIABLES |
| 88 | +int inputHigh = 0; |
| 89 | +int inputLow = 0; |
| 90 | +uint16_t inputChecksum = 0; // variable to caclulate checksum input variables |
| 91 | +uint16_t concPM1_0_CF1; // Lots of sensor variables |
| 92 | +uint16_t concPM2_5_CF1; |
| 93 | +uint16_t concPM10_0_CF1; |
| 94 | +uint16_t concPM1_0_amb; |
| 95 | +uint16_t concPM2_5_amb; |
| 96 | +uint16_t concPM10_0_amb; |
| 97 | +uint16_t rawGt0_3um; |
| 98 | +uint16_t rawGt0_5um; |
| 99 | +uint16_t rawGt1_0um; |
| 100 | +uint16_t rawGt2_5um; |
| 101 | +uint16_t rawGt5_0um; |
| 102 | +uint16_t rawGt10_0um; |
| 103 | +uint8_t version; |
| 104 | +uint8_t errorCode; |
| 105 | +uint16_t checksum; |
| 106 | +int dustSlowDownCounter = 0; |
| 107 | + |
| 108 | + |
| 109 | +void presentation() |
| 110 | +{ |
| 111 | + // Send the sketch version information to the gateway and Controller |
| 112 | + sendSketchInfo("Air Quality Sensor PMS-7003", "1.1"); |
| 113 | + |
| 114 | + // Register all sensors to gateway (they will be created as child devices): |
| 115 | + present(CHILD_ID_DUST_PM10, S_DUST); |
| 116 | + send(msgDust10b.set("um/m3")); |
| 117 | + present(CHILD_ID_DUST_PM25, S_DUST); |
| 118 | + send(msgDust25b.set("um/m3")); |
| 119 | + present(CHILD_ID_DUST_PM100, S_DUST); |
| 120 | + send(msgDust100b.set("um/m3")); |
| 121 | +} |
| 122 | + |
| 123 | + |
| 124 | +void setup() |
| 125 | +{ |
| 126 | + Serial.begin(115200); |
| 127 | + delay(1000); |
| 128 | + mySerial.begin(9600); |
| 129 | + delay(1000); |
| 130 | + Serial.println("hello world, I am a sensor."); |
| 131 | +} |
| 132 | + |
| 133 | + |
| 134 | +void loop() |
| 135 | +{ |
| 136 | + |
| 137 | + // The dust sensor sends its data continuously, so let's catch that data. |
| 138 | + int dustSensorOutput = pms7003ReadData(); |
| 139 | + |
| 140 | +} |
| 141 | + |
| 142 | + |
| 143 | +// MAIN FUNCTION FOR THE DUST SENSOR, Thanks to Scapeler.nl |
| 144 | +int pms7003ReadData() { |
| 145 | + |
| 146 | + // while (mySerial.read()!=-1) {}; //clear buffer |
| 147 | + |
| 148 | + if (mySerial.available() < 32) { |
| 149 | + if (mySerial.available() == 0) { |
| 150 | + delay(150); |
| 151 | + return -1; |
| 152 | + }; |
| 153 | + if (mySerial.available() > 16) { |
| 154 | + delay(10); |
| 155 | + return -1; |
| 156 | + }; |
| 157 | + if (mySerial.available() > 0) { |
| 158 | + delay(30); |
| 159 | + return -1; |
| 160 | + }; |
| 161 | + delay(100); |
| 162 | + return -1; |
| 163 | + } |
| 164 | + if (mySerial.read() != 0x42) return -1; |
| 165 | + if (mySerial.read() != 0x4D) return -1; |
| 166 | + |
| 167 | + inputChecksum = 0x42 + 0x4D; |
| 168 | + |
| 169 | + inputHigh = mySerial.read(); |
| 170 | + inputLow = mySerial.read(); |
| 171 | + inputChecksum += inputHigh + inputLow; |
| 172 | + if (inputHigh != 0x00) return -1; |
| 173 | + if (inputLow != 0x1c) return -1; |
| 174 | + |
| 175 | + inputHigh = mySerial.read(); |
| 176 | + inputLow = mySerial.read(); |
| 177 | + inputChecksum += inputHigh + inputLow; |
| 178 | + concPM1_0_CF1 = inputLow+(inputHigh<<8); |
| 179 | + |
| 180 | + inputHigh = mySerial.read(); |
| 181 | + inputLow = mySerial.read(); |
| 182 | + inputChecksum += inputHigh + inputLow; |
| 183 | + concPM2_5_CF1 = inputLow+(inputHigh<<8); |
| 184 | + |
| 185 | + inputHigh = mySerial.read(); |
| 186 | + inputLow = mySerial.read(); |
| 187 | + inputChecksum += inputHigh + inputLow; |
| 188 | + concPM10_0_CF1 = inputLow+(inputHigh<<8); |
| 189 | + |
| 190 | + inputHigh = mySerial.read(); |
| 191 | + inputLow = mySerial.read(); |
| 192 | + inputChecksum += inputHigh + inputLow; |
| 193 | + concPM1_0_amb = inputLow+(inputHigh<<8); |
| 194 | + |
| 195 | + inputHigh = mySerial.read(); |
| 196 | + inputLow = mySerial.read(); |
| 197 | + inputChecksum += inputHigh + inputLow; |
| 198 | + concPM2_5_amb = inputLow+(inputHigh<<8); |
| 199 | + |
| 200 | + inputHigh = mySerial.read(); |
| 201 | + inputLow = mySerial.read(); |
| 202 | + inputChecksum += inputHigh + inputLow; |
| 203 | + concPM10_0_amb = inputLow+(inputHigh<<8); |
| 204 | + |
| 205 | + inputHigh = mySerial.read(); |
| 206 | + inputLow = mySerial.read(); |
| 207 | + inputChecksum += inputHigh + inputLow; |
| 208 | + rawGt0_3um = inputLow+(inputHigh<<8); |
| 209 | + |
| 210 | + inputHigh = mySerial.read(); |
| 211 | + inputLow = mySerial.read(); |
| 212 | + inputChecksum += inputHigh + inputLow; |
| 213 | + rawGt0_5um = inputLow+(inputHigh<<8); |
| 214 | + |
| 215 | + inputHigh = mySerial.read(); |
| 216 | + inputLow = mySerial.read(); |
| 217 | + inputChecksum += inputHigh + inputLow; |
| 218 | + rawGt1_0um = inputLow+(inputHigh<<8); |
| 219 | + |
| 220 | + inputHigh = mySerial.read(); |
| 221 | + inputLow = mySerial.read(); |
| 222 | + inputChecksum += inputHigh + inputLow; |
| 223 | + rawGt2_5um = inputLow+(inputHigh<<8); |
| 224 | + |
| 225 | + inputHigh = mySerial.read(); |
| 226 | + inputLow = mySerial.read(); |
| 227 | + inputChecksum += inputHigh + inputLow; |
| 228 | + rawGt5_0um = inputLow+(inputHigh<<8); |
| 229 | + |
| 230 | + inputHigh = mySerial.read(); |
| 231 | + inputLow = mySerial.read(); |
| 232 | + inputChecksum += inputHigh + inputLow; |
| 233 | + rawGt10_0um = inputLow+(inputHigh<<8); |
| 234 | + |
| 235 | + inputLow = mySerial.read(); |
| 236 | + inputChecksum += inputLow; |
| 237 | + version = inputLow; |
| 238 | + |
| 239 | + inputLow = mySerial.read(); |
| 240 | + inputChecksum += inputLow; |
| 241 | + errorCode = inputLow; |
| 242 | + |
| 243 | + Serial.print("PMS7003;"); |
| 244 | + |
| 245 | + // The measurement recalculated to micrograms per cubic meter, a common standard. |
| 246 | + Serial.print(concPM1_0_CF1); |
| 247 | + Serial.print(';'); |
| 248 | + Serial.print(concPM2_5_CF1); |
| 249 | + Serial.print(';'); |
| 250 | + Serial.print(concPM10_0_CF1); |
| 251 | + Serial.print(';'); |
| 252 | + |
| 253 | + // The measurement recalculated to micrograms per cubic meter, a common standard. Not quite sure what the difference is.. |
| 254 | + Serial.print(concPM1_0_amb); |
| 255 | + Serial.print(';'); |
| 256 | + Serial.print(concPM2_5_amb); |
| 257 | + Serial.print(';'); |
| 258 | + Serial.print(concPM10_0_amb); |
| 259 | + Serial.print(';'); |
| 260 | + |
| 261 | + // this is the 'raw' data that the sensor gathers internally, before it calculates the above values. |
| 262 | + Serial.print(rawGt0_3um); // This indicates total number or particles in 0.1 liter of air that have a diameter above 0.3um. This will be the biggest number, as it measures the most particles. But it's very imprecise: 50% accuracy.. |
| 263 | + Serial.print(';'); |
| 264 | + Serial.print(rawGt0_5um); // This indicates the total number or particles in 0.1 liter of air that have a diameter above 0.5um (so it will be a smaller count than the line above) |
| 265 | + Serial.print(';'); |
| 266 | + Serial.print(rawGt1_0um); // This indicates the total number or particles in 0.1 liter of air that have a diameter above 1 micron. And so on.. |
| 267 | + Serial.print(';'); |
| 268 | + Serial.print(rawGt2_5um); |
| 269 | + Serial.print(';'); |
| 270 | + Serial.print(rawGt5_0um); // Acording to the datashet, at this point the accuracy has reached at 98%. |
| 271 | + Serial.print(';'); |
| 272 | + Serial.print(rawGt10_0um); |
| 273 | + Serial.print(';'); |
| 274 | + Serial.print(version); |
| 275 | + Serial.print(';'); |
| 276 | + Serial.print(errorCode); |
| 277 | + Serial.println("---"); |
| 278 | + |
| 279 | + inputHigh = mySerial.read(); |
| 280 | + inputLow = mySerial.read(); |
| 281 | + checksum = inputLow+(inputHigh<<8); |
| 282 | + if (checksum != inputChecksum) { |
| 283 | + Serial.print(';'); |
| 284 | + Serial.print(checksum); |
| 285 | + Serial.print(';'); |
| 286 | + Serial.print(inputChecksum); |
| 287 | + } |
| 288 | + |
| 289 | + // Time to send the results to the gateway. |
| 290 | + dustSlowDownCounter = dustSlowDownCounter + 1; |
| 291 | + if(dustSlowDownCounter > dustSlowDown) { |
| 292 | + |
| 293 | + /* MEASUREMENT */ |
| 294 | + if(rawGt1_0um > 0) { |
| 295 | + Serial.println(" Dust1_0 = " + String(concPM1_0_CF1)); |
| 296 | + send(msgDust10.set(concPM1_0_CF1,1)); |
| 297 | + } |
| 298 | + if(rawGt2_5um > 0){ |
| 299 | + Serial.println(" Dust1_0 = " + String(concPM2_5_CF1)); |
| 300 | + send(msgDust25.set(concPM2_5_CF1,1)); |
| 301 | + } |
| 302 | + if(rawGt10_0um > 0){ |
| 303 | + Serial.println(" Dust1_0 = " + String(concPM10_0_CF1)); |
| 304 | + send(msgDust100.set(concPM10_0_CF1,1)); |
| 305 | + } |
| 306 | + |
| 307 | + /* RAW DATA */ |
| 308 | + /* |
| 309 | + if(rawGt0_3um > 0) { |
| 310 | + Serial.println(" Dust03 = " + String(rawGt0_3um)); |
| 311 | + send(msgDust03.set(rawGt0_3um,1)); |
| 312 | + } |
| 313 | + if(rawGt0_5um > 0) { |
| 314 | + Serial.println(" Dust05 = " + String(rawGt0_5um)); |
| 315 | + send(msgDust05.set(rawGt0_5um,1)); |
| 316 | + } |
| 317 | + if(rawGt1_0um > 0) { |
| 318 | + Serial.println(" Dust10 = " + String(rawGt1_0um)); |
| 319 | + send(msgDust10.set(rawGt1_0um,1)); |
| 320 | + } |
| 321 | + if(rawGt2_5um > 0) { |
| 322 | + Serial.println(" Dust25 = " + String(rawGt2_5um)); |
| 323 | + send(msgDust25.set(rawGt2_5um,1)); |
| 324 | + } |
| 325 | + if(rawGt5_0um > 0) { |
| 326 | + Serial.println(" Dust50 = " + String(rawGt5_0um)); |
| 327 | + send(msgDust50.set(rawGt5_0um,1)); |
| 328 | + } |
| 329 | + if(rawGt10_0um > 0) { |
| 330 | + Serial.println(" Dust100 = " + String(rawGt10_0um)); |
| 331 | + send(msgDust100.set(rawGt10_0um,1)); |
| 332 | + } |
| 333 | + */ |
| 334 | + |
| 335 | + dustSlowDownCounter = 0; |
| 336 | + } // End of sensing message. |
| 337 | + |
| 338 | + delay(700); // Data will come between 200 and 800 miliseconds. If you set this be be higher than 700 you will get checksum errors. |
| 339 | + |
| 340 | + return concPM2_5_CF1; // this data doesn't really go anywhere.. |
| 341 | +} |
| 342 | + |
| 343 | + |
| 344 | + |
0 commit comments