Skip to content

Instantly share code, notes, and snippets.

@jywarren
Last active December 14, 2021 19:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jywarren/d9cdc98a4a50d8505ad04521e45ce59d to your computer and use it in GitHub Desktop.
Save jywarren/d9cdc98a4a50d8505ad04521e45ce59d to your computer and use it in GitHub Desktop.
// On Leonardo/Micro or others with hardware serial, use those!
// uncomment this line:
// #define pmsSerial Serial1
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (TX pin on sensor), leave pin #3 disconnected
// comment these two lines if using hardware serial
#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(2, 3);
int redPin = 4; // d4
int greenPin = 5; // d5
int bluePin = 7; // d7
#include <SoftModem.h>
SoftModem modem = SoftModem();
void setup() {
// our debugging output
Serial.begin(115200);
// sensor baud rate is 9600
pmsSerial.begin(9600);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
// start softmodem
delay(100);
modem.begin();
}
struct pms5003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
};
struct pms5003data data;
void loop() {
if (readPMSdata(&pmsSerial)) {
// reading data was successful!
Serial.println();
Serial.println("---------------------------------------");
Serial.println("Concentration Units (standard)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
Serial.println("---------------------------------------");
Serial.println("Concentration Units (environmental)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
Serial.println("---------------------------------------");
Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
Serial.println("---------------------------------------");
modem.print((String) data.pm10_standard + "," + data.pm25_standard + "," + data.pm100_standard);
int minVal = 0;
int maxVal = 20; // arbitrary
// map values to a portion of the 360 degree color wheel
int hue = max(0, min(359, map(data.pm25_standard, minVal, maxVal, 140, 0)));
setLedColorHSV(hue, 1, 1);
}
}
boolean readPMSdata(Stream *s) {
if (! s->available()) {
return false;
}
// Read a byte at a time until we get to the special '0x42' start-byte
if (s->peek() != 0x42) {
s->read();
return false;
}
// Now read all 32 bytes
if (s->available() < 32) {
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
s->readBytes(buffer, 32);
// get checksum ready
for (uint8_t i=0; i<30; i++) {
sum += buffer[i];
}
/* debugging
for (uint8_t i=2; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
*/
// The data comes in endian'd, this solves it so it works on all platforms
uint16_t buffer_u16[15];
for (uint8_t i=0; i<15; i++) {
buffer_u16[i] = buffer[2 + i*2 + 1];
buffer_u16[i] += (buffer[2 + i*2] << 8);
}
// put it into a nice struct :)
memcpy((void *)&data, (void *)buffer_u16, 30);
if (sum != data.checksum) {
Serial.println("Checksum failure");
return false;
}
// success!
return true;
}
// http://www.hobbitsandhobos.com/wp-content/uploads/2011/06/colorWheel.png
// Convert a given HSV (Hue Saturation Value) to RGB (Red Green Blue)
// and set the led to the color
// h is hue value, integer between 0 and 360
// s is saturation value, double between 0 and 1
// v is value, double between 0 and 1
// http://splinter.com.au/blog/?p=29
void setLedColorHSV(int h, double s, double v) {
double r=0;
double g=0;
double b=0;
double hf=h/60.0;
int i=(int)floor(h/60.0);
double f = h/60.0 - i;
double pv = v * (1 - s);
double qv = v * (1 - s*f);
double tv = v * (1 - s * (1 - f));
switch (i)
{
case 0: // rojo dominante
r = v;
g = tv;
b = pv;
break;
case 1: // verde
r = qv;
g = v;
b = pv;
break;
case 2:
r = pv;
g = v;
b = tv;
break;
case 3: // azul
r = pv;
g = qv;
b = v;
break;
case 4:
r = tv;
g = pv;
b = v;
break;
case 5: // rojo
r = v;
g = pv;
b = qv;
break;
}
// set each component to a integer value between 0 and 255
int red = constrain(255-(int)255*r,0,255);
int green = constrain(255-(int)255*g,0,255);
int blue = constrain(255-(int)255*b,0,255);
setLedColor(red,green,blue);
}
void setLedColor(int red, int green, int blue) {
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment