Skip to content

Commit ab6b868

Browse files
A new dust sensor for MySensors
This is a good sensor for the price. - The code is non-blocking. - Can it be integrated into MySensors with the use of code under an Apache license?
1 parent 38f1279 commit ab6b868

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

examples/PMS-7003 dust sensor

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
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+
// Are you using this sensor on battery power?
64+
// #define BATTERY_POWERED // Just remove the two slashes at the beginning of this line if your node is battery powered. It will then go into deep sleep as much as possible. While it's sleeping it can't work as a repeater!
65+
66+
#include <SPI.h>
67+
#include <MySensors.h>
68+
#include <SoftwareSerial.h>
69+
70+
#define CHILD_ID_DUST_PM10 0
71+
#define CHILD_ID_DUST_PM25 1
72+
#define CHILD_ID_DUST_PM100 2
73+
74+
75+
// Mysensors settings.
76+
MyMessage msgDust10(CHILD_ID_DUST_PM10, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later.
77+
MyMessage msgDust10b(CHILD_ID_DUST_PM10, V_UNIT_PREFIX);
78+
MyMessage msgDust25(CHILD_ID_DUST_PM25, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later.
79+
MyMessage msgDust25b(CHILD_ID_DUST_PM25, V_UNIT_PREFIX);
80+
MyMessage msgDust100(CHILD_ID_DUST_PM100, V_LEVEL); // Sets up the message format that we'l be sending to the MySensors gateway later.
81+
MyMessage msgDust100b(CHILD_ID_DUST_PM100, V_UNIT_PREFIX);
82+
83+
84+
85+
// These defines and variables can be changed:
86+
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?
87+
unsigned long dustMeasurementInterval = 700; // This is a fickle thing. Changing it can give more time-outs.
88+
SoftwareSerial mySerial(10, 11); // RX, TX . You can choose other pins if you prefer.
89+
90+
91+
// PROBABLY BEST NOT TO CHANGE THESE VARIABLES
92+
int inputHigh = 0;
93+
int inputLow = 0;
94+
uint16_t inputChecksum = 0; // variable to caclulate checksum input variables
95+
uint16_t concPM1_0_CF1; // Lots of sensor variables
96+
uint16_t concPM2_5_CF1;
97+
uint16_t concPM10_0_CF1;
98+
uint16_t concPM1_0_amb;
99+
uint16_t concPM2_5_amb;
100+
uint16_t concPM10_0_amb;
101+
uint16_t rawGt0_3um;
102+
uint16_t rawGt0_5um;
103+
uint16_t rawGt1_0um;
104+
uint16_t rawGt2_5um;
105+
uint16_t rawGt5_0um;
106+
uint16_t rawGt10_0um;
107+
uint8_t version;
108+
uint8_t errorCode;
109+
uint16_t checksum;
110+
int dustSlowDownCounter = 0;
111+
112+
113+
114+
void presentation()
115+
{
116+
// Send the sketch version information to the gateway and Controller
117+
sendSketchInfo("Air Quality Sensor PMS-7003", "1.1");
118+
119+
// Register all sensors to gateway (they will be created as child devices):
120+
present(CHILD_ID_DUST_PM10, S_DUST);
121+
send(msgDust10b.set("um/m3"));
122+
present(CHILD_ID_DUST_PM25, S_DUST);
123+
send(msgDust25b.set("um/m3"));
124+
present(CHILD_ID_DUST_PM100, S_DUST);
125+
send(msgDust100b.set("um/m3"));
126+
}
127+
128+
129+
void setup() {
130+
Serial.begin(115200);
131+
delay(1000);
132+
mySerial.begin(9600);
133+
delay(1000);
134+
Serial.println("hello world, I am a sensor.");
135+
}
136+
137+
138+
void loop() {
139+
140+
// The dust sensor sends its data continuously, so let's catch that data.
141+
int dustSensorOutput = pms7003ReadData();
142+
143+
}
144+
145+
146+
// MAIN FUNCTION FOR THE DUST SENSOR, Thanks to Scapeler.nl
147+
int pms7003ReadData() {
148+
149+
// while (mySerial.read()!=-1) {}; //clear buffer
150+
151+
if (mySerial.available() < 32) {
152+
if (mySerial.available() == 0) {
153+
delay(150);
154+
return -1;
155+
};
156+
if (mySerial.available() > 16) {
157+
delay(10);
158+
return -1;
159+
};
160+
if (mySerial.available() > 0) {
161+
delay(30);
162+
return -1;
163+
};
164+
delay(100);
165+
return -1;
166+
}
167+
if (mySerial.read() != 0x42) return -1;
168+
if (mySerial.read() != 0x4D) return -1;
169+
170+
inputChecksum = 0x42 + 0x4D;
171+
172+
inputHigh = mySerial.read();
173+
inputLow = mySerial.read();
174+
inputChecksum += inputHigh + inputLow;
175+
if (inputHigh != 0x00) return -1;
176+
if (inputLow != 0x1c) return -1;
177+
178+
inputHigh = mySerial.read();
179+
inputLow = mySerial.read();
180+
inputChecksum += inputHigh + inputLow;
181+
concPM1_0_CF1 = inputLow+(inputHigh<<8);
182+
183+
inputHigh = mySerial.read();
184+
inputLow = mySerial.read();
185+
inputChecksum += inputHigh + inputLow;
186+
concPM2_5_CF1 = inputLow+(inputHigh<<8);
187+
188+
inputHigh = mySerial.read();
189+
inputLow = mySerial.read();
190+
inputChecksum += inputHigh + inputLow;
191+
concPM10_0_CF1 = inputLow+(inputHigh<<8);
192+
193+
inputHigh = mySerial.read();
194+
inputLow = mySerial.read();
195+
inputChecksum += inputHigh + inputLow;
196+
concPM1_0_amb = inputLow+(inputHigh<<8);
197+
198+
inputHigh = mySerial.read();
199+
inputLow = mySerial.read();
200+
inputChecksum += inputHigh + inputLow;
201+
concPM2_5_amb = inputLow+(inputHigh<<8);
202+
203+
inputHigh = mySerial.read();
204+
inputLow = mySerial.read();
205+
inputChecksum += inputHigh + inputLow;
206+
concPM10_0_amb = inputLow+(inputHigh<<8);
207+
208+
inputHigh = mySerial.read();
209+
inputLow = mySerial.read();
210+
inputChecksum += inputHigh + inputLow;
211+
rawGt0_3um = inputLow+(inputHigh<<8);
212+
213+
inputHigh = mySerial.read();
214+
inputLow = mySerial.read();
215+
inputChecksum += inputHigh + inputLow;
216+
rawGt0_5um = inputLow+(inputHigh<<8);
217+
218+
inputHigh = mySerial.read();
219+
inputLow = mySerial.read();
220+
inputChecksum += inputHigh + inputLow;
221+
rawGt1_0um = inputLow+(inputHigh<<8);
222+
223+
inputHigh = mySerial.read();
224+
inputLow = mySerial.read();
225+
inputChecksum += inputHigh + inputLow;
226+
rawGt2_5um = inputLow+(inputHigh<<8);
227+
228+
inputHigh = mySerial.read();
229+
inputLow = mySerial.read();
230+
inputChecksum += inputHigh + inputLow;
231+
rawGt5_0um = inputLow+(inputHigh<<8);
232+
233+
inputHigh = mySerial.read();
234+
inputLow = mySerial.read();
235+
inputChecksum += inputHigh + inputLow;
236+
rawGt10_0um = inputLow+(inputHigh<<8);
237+
238+
inputLow = mySerial.read();
239+
inputChecksum += inputLow;
240+
version = inputLow;
241+
242+
inputLow = mySerial.read();
243+
inputChecksum += inputLow;
244+
errorCode = inputLow;
245+
246+
Serial.print("PMS7003;");
247+
248+
// The measurement recalculated to micrograms per cubic meter, a common standard.
249+
Serial.print(concPM1_0_CF1);
250+
Serial.print(';');
251+
Serial.print(concPM2_5_CF1);
252+
Serial.print(';');
253+
Serial.print(concPM10_0_CF1);
254+
Serial.print(';');
255+
256+
// The measurement recalculated to micrograms per cubic meter, a common standard. Not quite sure what the difference is..
257+
Serial.print(concPM1_0_amb);
258+
Serial.print(';');
259+
Serial.print(concPM2_5_amb);
260+
Serial.print(';');
261+
Serial.print(concPM10_0_amb);
262+
Serial.print(';');
263+
264+
// this is the 'raw' data that the sensor gathers internally, before it calculates the above values.
265+
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..
266+
Serial.print(';');
267+
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)
268+
Serial.print(';');
269+
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..
270+
Serial.print(';');
271+
Serial.print(rawGt2_5um);
272+
Serial.print(';');
273+
Serial.print(rawGt5_0um); // Acording to the datashet, at this point the accuracy has reached at 98%.
274+
Serial.print(';');
275+
Serial.print(rawGt10_0um);
276+
Serial.print(';');
277+
Serial.print(version);
278+
Serial.print(';');
279+
Serial.print(errorCode);
280+
Serial.println("---");
281+
282+
inputHigh = mySerial.read();
283+
inputLow = mySerial.read();
284+
checksum = inputLow+(inputHigh<<8);
285+
if (checksum != inputChecksum) {
286+
Serial.print(';');
287+
Serial.print(checksum);
288+
Serial.print(';');
289+
Serial.print(inputChecksum);
290+
}
291+
292+
// Time to send the results to the gateway.
293+
dustSlowDownCounter = dustSlowDownCounter + 1;
294+
if(dustSlowDownCounter > dustSlowDown){
295+
296+
/* MEASUREMENT */
297+
if(rawGt1_0um > 0){
298+
Serial.println(" Dust1_0 = " + String(concPM1_0_CF1));
299+
send(msgDust10.set(concPM1_0_CF1,1));
300+
}
301+
if(rawGt2_5um > 0){
302+
Serial.println(" Dust1_0 = " + String(concPM2_5_CF1));
303+
send(msgDust25.set(concPM2_5_CF1,1));
304+
}
305+
if(rawGt10_0um > 0){
306+
Serial.println(" Dust1_0 = " + String(concPM10_0_CF1));
307+
send(msgDust100.set(concPM10_0_CF1,1));
308+
}
309+
310+
/* RAW DATA */
311+
/*
312+
if(rawGt0_3um > 0){
313+
Serial.println(" Dust03 = " + String(rawGt0_3um));
314+
send(msgDust03.set(rawGt0_3um,1));
315+
}
316+
if(rawGt0_5um > 0){
317+
Serial.println(" Dust05 = " + String(rawGt0_5um));
318+
send(msgDust05.set(rawGt0_5um,1));
319+
}
320+
if(rawGt1_0um > 0){
321+
Serial.println(" Dust10 = " + String(rawGt1_0um));
322+
send(msgDust10.set(rawGt1_0um,1));
323+
}
324+
if(rawGt2_5um > 0){
325+
Serial.println(" Dust25 = " + String(rawGt2_5um));
326+
send(msgDust25.set(rawGt2_5um,1));
327+
}
328+
if(rawGt5_0um > 0){
329+
Serial.println(" Dust50 = " + String(rawGt5_0um));
330+
send(msgDust50.set(rawGt5_0um,1));
331+
}
332+
if(rawGt10_0um > 0){
333+
Serial.println(" Dust100 = " + String(rawGt10_0um));
334+
send(msgDust100.set(rawGt10_0um,1));
335+
}
336+
*/
337+
338+
dustSlowDownCounter = 0;
339+
} // End of sensing message.
340+
341+
delay(700); // Data will come between 200 and 800 miliseconds. If you set this be be higher than 700 you will get checksum errors.
342+
343+
return concPM2_5_CF1; // this data doesn't really go anywhere..
344+
}
345+
346+
347+

0 commit comments

Comments
 (0)