Files
ESPEasy/lib/SerialDevices/jkSDS011.cpp
T
fcauwe 2bcad48eab [P056] Fixed bug when SDS sensor is not reporting
Fixed bug that makes the sensor not reporting values even when everything is well connected.
The problem is that the Sensor is in "Query reporting" mode, and therefore it is not actively sending values.
The fix consist of setting the Sensor in "Active reporting" (command 2,1,0), when setting the working during configuration.
2020-11-15 10:51:22 +01:00

199 lines
5.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*-------------------------------------------------------------------------
Arduino library to ...
Written by Jochen Krapf,
contributions by ... and other members of the open
source community.
-------------------------------------------------------------------------
This file is part of the MechInputs library.
MechInputs is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
MechInputs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with MechInputs. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
//#ifdef ESP8266 // Needed for precompile issues.
#include "jkSDS011.h"
CjkSDS011::CjkSDS011(ESPEasySerialPort port, int16_t pinRX, int16_t pinTX)
{
_sws = ! ( pinRX < 0 || pinRX == 3 );
_pm2_5 = NAN;
_pm10_ = NAN;
_available = false;
_pm2_5avr = 0;
_pm10_avr = 0;
_avr = 0;
_data.SetPacketLength(10);
_command.SetPacketLength(19);
_working_period = -1;
_sleepmode_active = false;
_serial = new (std::nothrow) ESPeasySerial(port, pinRX, pinTX);
if (_serial != nullptr)
_serial->begin(9600);
}
CjkSDS011::~CjkSDS011() {
delete _serial;
}
void CjkSDS011::SendCommand(byte byte1, byte byte2, byte byte3) {
_command[0] = 0xAA; // Head
_command[1] = 0xB4; // Command ID
_command[2] = byte1; // Data Byte 1
_command[3] = byte2; // Data Byte 2
_command[4] = byte3; // Data Byte 3
_command[5] = 0; // Data Byte 4
_command[6] = 0; // Data Byte 5
_command[7] = 0; // Data Byte 6
_command[8] = 0; // Data Byte 7
_command[9] = 0; // Data Byte 8
_command[10] = 0; // Data Byte 9
_command[11] = 0; // Data Byte 10
_command[12] = 0; // Data Byte 11
_command[13] = 0; // Data Byte 12
_command[14] = 0; // Data Byte 13
_command[15] = 0xFF; // Device ID byte 1, FF: All sensor response
_command[16] = 0xFF; // Device ID byte 2, FF: All sensor response
byte checksum = 0;
for (byte i=2; i< 17; ++i) {
checksum += _command[i];
}
_command[17] = checksum; // Checksum
_command[18] = 0xAB; // Tail
for (int i = 0; i < 19; ++i) {
_serial->write(_command[i]);
}
}
void CjkSDS011::SetSleepMode(bool enabled) {
byte databyte3 = enabled ? 0 : 1;
SendCommand(6, 1, databyte3);
}
void CjkSDS011::SetWorkingPeriod(int minutes) {
// Data byte 1: 8
// Data byte 2: 0: query the current mode
// 1: set mode
// Data byte 3: 0continuous(default)
// 1-30minutework 30 seconds and sleep n*60-30 seconds
if (minutes < 0 || minutes > 30) return;
// Working period is stored in the flash of the sensor. Only write to change.
const int currentWorkingPeriod = GetWorkingPeriod();
if (minutes != currentWorkingPeriod)
SendCommand(8, 1, minutes);
// In some cases the Sensor is set to "report query"-mode, this makes sure to set active reporting of values, otherwise the sensor won't work.
Process();
SendCommand(2, 1, 0);
}
int CjkSDS011::GetWorkingPeriod() {
// Data byte 1: 8
// Data byte 2: 0: query the current mode
// 1: set mode
// Data byte 3: 0continuous(default)
// 1-30minutework 30 seconds and sleep n*60-30 seconds
SendCommand(8, 0, 0);
Process();
return _working_period;
}
void CjkSDS011::ParseCommandReply() {
switch(_data[2]) {
case 6: // Enable/Disable sleep mode.
if (_data[3] == 0)
_sleepmode_active = _data[4];
break;
case 8: // Set/Get working period
if (_data[3] == 0)
_working_period = _data[4];
break;
default:
// Not implemented.
break;
}
}
void CjkSDS011::Process()
{
int serial_available = _serial->available();
while (serial_available > 0)
{
--serial_available;
_data.AddData(_serial->read());
if (_data[0] == 0xAA && _data[9] == 0xAB) // correct packet frame?
{
byte checksum = 0;
for (byte i=2; i<= 7; i++)
checksum += _data[i];
if (checksum != _data[8])
continue;
switch(_data[1]) {
case 0xC0: // SDS011 or SDS018?
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
_available = true;
break;
case 0xCF: // SDS198?
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
_pm10_ = (float)((_data[3] << 8) | _data[2]);
_available = true;
break;
case 0xC5: // Reply on command ID 0xB4
ParseCommandReply();
break;
default:
break;
}
if (_available) {
_pm2_5avr += _pm2_5;
_pm10_avr += _pm10_;
_avr++;
_data.Clear();
return;
}
}
if (serial_available == 0) {
serial_available = _serial->available();
}
}
}
boolean CjkSDS011::available()
{
boolean ret = _available;
_available = false;
return ret;
}
boolean CjkSDS011::ReadAverage(float &pm25, float &pm10)
{
if (_avr)
{
pm25 = _pm2_5avr / _avr;
pm10 = _pm10_avr / _avr;
_pm2_5avr = 0;
_pm10_avr = 0;
_avr = 0;
return true;
}
pm25 = NAN;
pm10 = NAN;
return false;
}
// #endif