Skip to content

Commit 124c03c

Browse files
authored
Merge pull request mysensors#27 from flatsiedatsie/patch-5
A new dust sensor for MySensors
2 parents df5e379 + 5b0ba2f commit 124c03c

File tree

1 file changed

+344
-0
lines changed

1 file changed

+344
-0
lines changed

examples/PMS-7003 dust sensor

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
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

Comments
 (0)