jbanaszczyk / pms5003 Goto Github PK
View Code? Open in Web Editor NEWArduino: PMS5003 Air Quality Sensor library.
License: Boost Software License 1.0
Arduino: PMS5003 Air Quality Sensor library.
License: Boost Software License 1.0
Hi, this is probably a totally stupid beginner question, but I'm working with the basic sketch and want to publish the PM data with MQTT and want to add pmsIdx as part of the topic to get for each i the relevant topic such as /livingroom/PMS7003/PM1dot0 etc.
I tried (successfully) with dataNames but that is the description and not Idx...
for (size_t i = Pmsx003::PM1dot0; i < n; ++i) {
Serial.print(data[i]);
Serial.print("\t");
Serial.print(Pmsx003::dataNames[i]);
Serial.print(" [");
Serial.print(Pmsx003::metrics[i]);
Serial.println();
String topic_send = topic_root;
topic_send += Pmsx003::dataNames[i];
Serial.print("Sending via ");
Serial.println(topic_send);
client.publish(String(topic_send).c_str(), String(data[i]).c_str(),true);
}
Thanks for any help!
Hello,
I went through the spec sheet of the PMS5003 and I have a couple of question about sleep/wake that I couldn't find in the specsheet neither the lib documentation and I hope you can help me with them.
If I use pm01basic sketch it works fine. But if I move read procedure out of void loop(void) to new readPMS() function I receiving CRC Error quite often. Even more: after 10 - 15 minutes I receiving "Pms error: CRC Error" all the time.
How can I move read procedure out of main loop?
Thank You!
Great job - thank you! Just chage name of examples from "01_Simple" to "Simple" due to Arduino IDE requirements.
Hello, I am trying to use this library for my PMS sensors and have run into a problem. I am using the modified AltSoftSerial Library as suggested. But when i try to compile i am getting this error.
Arduino: 1.6.5 (Windows 8.1), Board: "Arduino/Genuino Uno"
Build options changed, rebuilding all
In file included from C:\Program Files (x86)\Arduino\libraries\pms5003-master\src/pms.h:7:0,
from PMS5003_1.ino:3:
C:\Program Files (x86)\Arduino\libraries\pms5003-master\src/pmsConfig.h:37:27: fatal error: >AltSoftSerial.h: No such file or directory
#include <AltSoftSerial.h>
^
compilation terminated.
Error compiling.
Could you please help me as to what might be going wrong?
Thank you so much
Is this library compatible with ESP32? How to connect the sensor to ESP32?
Great work! Would you check the following error (in Arduino IDE version 1.8.1):
\Documents\Arduino\libraries\pms5003-master\src\pms.cpp: In member function 'bool Pms5003::begin()':
\Documents\Arduino\libraries\pms5003-master\src\pms.cpp:73:27: error: could not convert 'AltSoftSerial::begin(9600ul)' from 'void' to 'bool'
if (!pmsSerial.begin(9600)) {
^
C:\Users\Robert\Documents\Arduino\libraries\pms5003-master\src\pms.cpp:73:27: error: in argument to unary !
https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ
Would be nice if this library could be updated via Arduino IDE
So minor but took me a while to figure out. On case sensitive file systems it uses arduino.h in one of the installed packages instead of Arduino.h which cased confusing errors.
I'll need a bit of help to adapt/make this library working with
PMS5003I and PMS7003I, but I am mostly hardware guy and don't
really have expereince with write/modify libraries.
I wrote in the Arduino forum and understood it is not impossible
but will need some work to be done.
I do connect 5003I to Arduino Uno (via level adapter) and I2C
scanner successfully found 0x12 address which those sensors have.
How can advice me to go further?
lib/pms5003/src/pms.h:44:7: error: use of enum 'PmsCmd' without previous declaration
enum PmsCmd : __uint24 {
^
lib/pms5003/src/pms.h:44:16: error: '__uint24' was not declared in this scope
enum PmsCmd : __uint24 {
^
On PlatformIO ESP8266
Do you plan to make library compatible with Arduino Mega 2560? If i use it on Mega i cannot retrieve data from the sensor (case Pms5003::noData:). Is there any special requirements for Mega? Thank you!
As it is listed in PMSStatus codes there is all codes except CRC Error. It happens quite often in my case. Do you have any idea what is the cause of this error and how can I avoid it?
Anyway, thank you for excellent library!
It'd be great if an ESP8266-compatible version could be made in the future, as these sensors are great for wireless sensor stations.
I made a modification to the 1.0 version of the library to remove dependencies on Software serial and replaced it with "Serial1" to use hardware serial provided by Adafruit feather.
Sometimes, the library returns PM1.0 value of 16973 (i.e. 0x424d)... is this a side effect of switching to hardware serial or is this an issue with the core library code? As I understand it, 0x424d is a special value of some kind.
I also intermittently receive other oddly high (but random) values, which I assume are value transcription errors as well.
Any information would be appreciated.
Modified code, below:
#include "pms.h"
////////////////////////////////////////
#if defined NOMINMAX
#if defined min
#undef min
#endif
template <class T> inline const T& __attribute__((always_inline)) min(const T& a, const T& b);
template <class T> inline const T& __attribute__((always_inline)) min(const T& a, const T& b) {
return !(b < a) ? a : b;
}
#endif
////////////////////////////////////////
inline void __attribute__((always_inline)) swapEndianBig16(uint16_t *x) {
constexpr union {
// endian.test16 == 0x0001 for low endian
// endian.test16 == 0x0100 for big endian
// should be properly optimized by compiler
uint16_t test16;
uint8_t test8[2];
} endian = { .test8 = { 1,0 } };
if (endian.test16 != 0x0100) {
uint8_t hi = (*x & 0xff00) >> 8;
uint8_t lo = (*x & 0xff);
*x = lo << 8 | hi;
}
}
////////////////////////////////////////
void sumBuffer(uint16_t *sum, const uint8_t *buffer, uint16_t cnt) {
for (; cnt > 0; --cnt, ++buffer) {
*sum += *buffer;
}
}
inline void sumBuffer(uint16_t *sum, const uint16_t data) {
*sum += (data & 0xFF) + (data >> 8);
}
////////////////////////////////////////
void Pms5003::setTimeout(const decltype(timeout) timeout) {
Serial1.setTimeout(timeout);
this->timeout = timeout;
};
decltype(Pms5003::timeout) Pms5003::getTimeout(void) const {
return timeout;
};
Pms5003::Pms5003() : passive(tribool(unknown)), sleep(tribool(unknown)) {
#if defined PMS_DYNAMIC
begin();
#endif
};
Pms5003::~Pms5003() {
#if defined PMS_DYNAMIC
end();
#endif
}
bool Pms5003::begin(void)
{
Serial1.setTimeout(Pms5003::timeoutPassive);
Serial1.begin(9600);
return true;
};
void Pms5003::end(void) {
Serial1.end();
};
size_t Pms5003::available(void) {
while (Serial1.available()) {
if (Serial1.peek() != sig[0]) {
Serial1.read();
} else {
break;
}
}
return static_cast<size_t>(Serial1.available());
}
Pms5003::PmsStatus Pms5003::read(pmsData *data, const size_t nData, const uint8_t dataSize) {
if (available() < (dataSize + 2) * sizeof(pmsData) + sizeof(sig)) {
return noData;
}
Serial1.read(); // Value is equal to sig[0]. There is no need to check the value, it was checked by prior peek()
if (Serial1.read() != sig[1]) // The rest of the buffer will be invalidated during the next read attempt
return readError;
uint16_t sum{ 0 };
sumBuffer(&sum, (uint8_t *)&sig, sizeof(sig));
pmsData thisFrameLen{ 0x1c };
if (Serial1.readBytes((uint8_t*)&thisFrameLen, sizeof(thisFrameLen)) != sizeof(thisFrameLen)) {
return readError;
};
if (thisFrameLen % 2 != 0) {
return frameLenMismatch;
}
sumBuffer(&sum, thisFrameLen);
const decltype(thisFrameLen) maxFrameLen{ 2 * 0x1c }; // arbitrary
swapEndianBig16(&thisFrameLen);
if (thisFrameLen > maxFrameLen) {
return frameLenMismatch;
}
size_t toRead{ min(thisFrameLen - 2, nData * sizeof(pmsData)) };
if (data == nullptr) {
toRead = 0;
}
if (toRead) {
if (Serial1.readBytes((uint8_t*)data, toRead) != toRead) {
return readError;
}
sumBuffer(&sum, (uint8_t*)data, toRead);
for (size_t i = 0; i < nData; ++i) {
swapEndianBig16(&data[i]);
}
}
pmsData crc;
for (; toRead < thisFrameLen; toRead += 2) {
if (Serial1.readBytes((uint8_t*)&crc, sizeof(crc)) != sizeof(crc)) {
return readError;
};
if (toRead < thisFrameLen - 2)
sumBuffer(&sum, crc);
}
swapEndianBig16(&crc);
if (sum != crc) {
return sumError;
}
return OK;
}
void Pms5003::flushInput(void) {
}
bool Pms5003::waitForData(const unsigned int maxTime, const size_t nData) {
const auto t0 = millis();
if (nData == 0) {
for (; (millis() - t0) < maxTime; delay(1)) {
if (Serial1.available()) {
return true;
}
}
return Serial1.available();
}
for (; (millis() - t0) < maxTime; delay(1)) {
if (available() >= nData) {
return true;
}
}
return available() >= nData;
}
bool Pms5003::write(const PmsCmd cmd) {
static_assert(sizeof(cmd) >= 3, "Wrong definition of PmsCmd (too short)");
if ((cmd != cmdReadData) && (cmd != cmdWakeup)) {
flushInput();
}
if (Serial1.write(sig, sizeof(sig)) != sizeof(sig)) {
return false;
}
const size_t cmdSize = 3;
if (Serial1.write((uint8_t*)&cmd, cmdSize) != cmdSize) {
return false;
}
uint16_t sum{ 0 };
sumBuffer(&sum, sig, sizeof(sig));
sumBuffer(&sum, (uint8_t*)&cmd, cmdSize);
swapEndianBig16(&sum);
if (Serial1.write((uint8_t*)&sum, sizeof(sum)) != sizeof(sum)) {
return false;
}
switch (cmd) {
case cmdModePassive:
passive = tribool(true);
break;
case cmdModeActive:
passive = tribool(false);
break;
case cmdSleep:
sleep = tribool(true);
break;
case cmdWakeup:
sleep = tribool(false);
passive = tribool(false);
// waitForData(wakeupTime);
break;
default:
break;
}
if ((cmd != cmdReadData) && (cmd != cmdWakeup)) {
const auto responseFrameSize = 8;
if (!waitForData(ackTimeout, responseFrameSize)) {
return true;
}
Pms5003::pmsData response = 0xCCCC;
read(&response, 1, 1);
}
/*
if ((cmd != cmdReadData) && (cmd != cmdWakeup)) {
const auto responseFrameSize = 8;
if (!waitForData(ackTimeout, responseFrameSize)) {
Serial1.flushInput();
return false;
}
Pms5003::pmsData response = 0xCCCC;
if (read(&response, 1, 1) != OK) {
return false;
}
if ((response >> 8) != (cmd & 0xFF)) {
return false;
}
}
*/
return true;
}
const char *Pms5003::getMetrics(const pmsIdx idx) {
return idx < nValues_PmsDataNames ? Pms5003::metrics[idx] : "???";
}
const char *Pms5003::getDataNames(const pmsIdx idx) {
return idx < nValues_PmsDataNames ? Pms5003::dataNames[idx] : "???";
}
const char * Pms5003::errorMsg[nValues_PmsStatus]{
"OK",
"noData",
"readError",
"frameLenMismatch",
"sumError"
};
const char *Pms5003::metrics[]{
"mcg/m3",
"mcg/m3",
"mcg/m3",
"mcg/m3",
"mcg/m3",
"mcg/m3",
"/0.1L",
"/0.1L",
"/0.1L",
"/0.1L",
"/0.1L",
"/0.1L",
"???"
};
const char *Pms5003::dataNames[]{
"PM1.0, CF=1",
"PM2.5, CF=1",
"PM10. CF=1",
"PM1.0",
"PM2.5",
"PM10.",
"Particles > 0.3 micron",
"Particles > 0.5 micron",
"Particles > 1.0 micron",
"Particles > 2.5 micron",
"Particles > 5.0 micron",
"Particles > 10. micron",
"Reserved_0"
};
Hi,
I love the library and try to put together a script that allows to have the PMS sleep for a while. I simply want to measure PM only every - say - 10min and then go to (deep) sleep.
But I am struggling to realize this. At the moment I am working with delay() but that has the effect, that "something times out" and I do not get ANY readings.
I want to realize that the ESP8266 wakes up, waits an appropriate time so the sensor can get ready to get proper readings and then pulls data, maybe waits 30 sec to get another data sample, and another sample after 30 sec and then sleeps (fan off) and the ESP8266 goes to deep sleep, too.
How could I realize this properly without using delay()?
Many thanks in advance!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.