-
-
Save hfiennes/7f8892b1856961b53c26b23d14ef60ee to your computer and use it in GitHub Desktop.
Sensirion SPS30 air quality sensor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Sensirion SPS30 air quality sensor | |
// hugo@electricimp.com | |
// uartABCD is on Grove J9 | |
uart <- hardware.uartABCD; | |
// Current serial state and collected packet | |
state <- -1; | |
packet <- ""; | |
// Send a packet to the sensor; this does the checksum calculation, stuffing, and HDLC framing | |
function sendpacket(addr, cmd, data) { | |
// Form core of packet | |
local packet = format("%c%c%c%s", addr, cmd, data.len(), data); | |
// Calculate checksum | |
local chk = 0; | |
foreach(c in packet) chk += c; | |
packet += format("%c", chk ^ 0xff); | |
// Byte-stuff as needed | |
local stuffed = ""; | |
foreach(c in packet) { | |
if (c == 0x7d || c == 0x7e || c == 0x11 || c == 0x13) { | |
// Stuff it | |
stuffed += "\x7d"+(c ^ 0x20).tochar(); | |
} else { | |
// No need to stuff | |
stuffed += c.tochar(); | |
} | |
} | |
// Send it with start and stop | |
uart.write("\x7e"+stuffed+"\x7e"); | |
} | |
// Callback to deal with receiving a single byte | |
function rx() { | |
local b = uart.read(); | |
// Waiting for start of a packet? | |
if (state == -1) { | |
// Packets always start with 0x7e | |
if (b == 0x7e) { | |
packet = ""; | |
state++; | |
return; | |
} | |
} | |
// Collect bytes until another 0x7e | |
if (b != 0x7e) packet += b.tochar(); | |
else { | |
// Did we just see another 0x7e, with nothing collected? | |
// We're getting back in sync | |
if (packet == "") return; | |
// Process the received packet & reset state | |
rxpacket(packet); | |
state = -1; | |
} | |
} | |
// We've got a whole packet, check that it's valid | |
function rxpacket(pkt) { | |
// Unstuff packet | |
local unstuffed = ""; | |
local xor = 0; | |
foreach(c in pkt) { | |
if (c == 0x7d) xor = 0x20; | |
else { | |
// Unstuff if needed, reset stuff indicator | |
unstuffed += (c ^ xor).tochar(); | |
xor = 0; | |
} | |
} | |
// Remove checksum from received packet | |
local rxchk = unstuffed[unstuffed.len()-1]; | |
unstuffed = unstuffed.slice(0, unstuffed.len()-1); | |
// Calculate checksum | |
local chk = 0; | |
foreach(c in unstuffed) chk += c; | |
chk = (chk & 0xff) ^ 0xff; | |
// Do they match? | |
if (chk == rxchk) { | |
// Process received packet | |
switch(unstuffed[1]) { | |
case 0x03: // Reading packet | |
// Check length is as expected | |
if (unstuffed.len() != 44) break; | |
// Move it into a blob to extract the floats | |
local b = blob(); | |
b.writestring(unstuffed.slice(4)); | |
b.seek(0, 'b'); | |
// Swap endianness | |
b.swap4(); | |
// Extract data: readings are IEEE754 floats | |
local reading = { | |
"mass_pm1_0": b.readn('f'), | |
"mass_pm2_5": b.readn('f'), | |
"mass_pm4_0": b.readn('f'), | |
"mass_pm10": b.readn('f'), | |
"number_pm0_5": b.readn('f'), | |
"number_pm1_0": b.readn('f'), | |
"number_pm2_5": b.readn('f'), | |
"number_pm4_0": b.readn('f'), | |
"number_pm10": b.readn('f'), | |
"typ_size": b.readn('f') | |
}; | |
// Send to agent | |
agent.send("telemetry", reading); | |
break; | |
} | |
} else { | |
server.log(format("chk error rx %02x calc %02x", rxchk, chk)) | |
} | |
} | |
// Configure UART and attach receive handler | |
uart.configure(115200, 8, PARITY_NONE, 1, NO_CTSRTS, rx); | |
const START_MEASUREMENT = 0x00; | |
const READ_MEASURED_VALUES = 0x03; | |
// Ensure fan is started | |
sendpacket(0, START_MEASUREMENT, "\x01\x03"); | |
// Every second, kick off a reading; the receive handler will collect the | |
// data, parse it, and send it to the cloud | |
function takereading() { | |
// Ask sensor for data | |
sendpacket(0, READ_MEASURED_VALUES, ""); | |
// Do it again in 10 seconds | |
imp.wakeup(10, takereading); | |
} | |
takereading(); | |
server.log("AQ sensor online"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment