cyberman54 / ESP32-Paxcounter

Wifi & BLE driven passenger flow metering with cheap ESP32 boards

Home Page:https://cyberman54.github.io/ESP32-Paxcounter/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SDS011 seems to only generate one reading and then returns 0 for all following readings

proffalken opened this issue · comments

Hello again :D

So, this time I've checked all the wiring and the power, and I've uploaded the sketch to my LILYGO v2.1 board.

The SDS011 spins up, and returns a reading the first time it runs, but then only returns 0 after that.

I've tried waiting for a few hours and seeing what happens in case its a delay in the SDS011 library, and I've swapped the SDS011 for a second one just in case it was the sensor itself, but the results are the same:

image

I've searched through the issues here as well and I can't see anything that relates to this, nor does there appear to be anything in the docs about specifically having to enable the SDS011 (unlike the BME680), so I'm at a loss as to what's causing this.

Relevant parts of the HAL file:

// SDS011 dust sensor settings
#define HAS_SDS011 1 // use SDS011
// used pins on the ESP-side:
#define SDS_TX GPIO_NUM_13     // connect to RX on the SDS011
#define SDS_RX GPIO_NUM_15     // connect to TX on the SDS011
#endif


// SDS011 dust sensor settings
#define HAS_SDS011 1 // use SDS011
// used pins on the ESP-side:
#define SDS_TX GPIO_NUM_13     // connect to RX on the SDS011
#define SDS_RX GPIO_NUM_15     // connect to TX on the SDS011
#endif

and paxcounter.conf:

// clang-format off

// ----- Paxcounter user config file ------
//
// --> adapt to your needs and use case <--
//
// Notes:
// 1. After editing, before "build", use "clean" button in PlatformIO!
// 2. Clear NVRAM of the board to delete previous stored runtime settings (pio run -t erase)

// Device options
#define VERBOSE                         1       // set to 0 to silence the device, 1 enables additional debug output
#define BOOTMENU                        0       // 0 = no bootmenu, 1 = device brings up boot menu before starting application
#define BOOTDELAY                       30      // time [seconds] while devices waits in boot menue for input
#define BOOTTIMEOUT                     300     // time [seconds] while devices waits to finish upload a firmware file
#define SDLOGGING                       0       // set to 1 for system logging to SD card (if device has one)

// Payload send cycle and encoding
#define SENDCYCLE                       150      // payload send cycle [seconds/2], 0 .. 255
#define SLEEPCYCLE                      10       // sleep time after a send cycle [seconds/10], 0 .. 65535; 0 means no sleep [default = 0]
#define PAYLOAD_ENCODER                 2       // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed
#define COUNTERMODE                     0       // 0=cyclic, 1=cumulative, 2=cyclic confirmed
#define SYNCWAKEUP                      300     // shifts sleep wakeup to top-of-hour, when +/- X seconds off [0=off]

// default settings for transmission of sensor data (first list = data on / second line = data off)
#define PAYLOADMASK                                                                             \
            ((GPS_DATA | MEMS_DATA | COUNT_DATA | SENSOR1_DATA | SENSOR2_DATA | SENSOR3_DATA) & \
            (~BATT_DATA) & (~RESERVED_DATA))

// MAC sniffing settings
#define BLECOUNTER                      1       // set to 0 if you do not want to start the BLE sniffer
#define WIFICOUNTER                     1       // set to 0 if you do not want to start the WIFI sniffer
#define RSSILIMIT                       0       // 0...-128, set to 0 if you do not want to filter signals

// BLE scan parameters
#define BLESCANTIME                     0       // [seconds] scan duration, 0 means infinite [default], see note below
#define BLESCANWINDOW                   80      // [milliseconds] scan window, see below, 3 .. 10240, default 80ms
#define BLESCANINTERVAL                 80      // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle

/* Note: guide for setting bluetooth parameters
*
* |< Scan Window >       |< Scan Window >       | ... |< Scan Window >       |
* |<    Scan Interval   >|<    Scan Interval   >| ... |<    Scan Interval   >|
* |<                   Scan duration                                        >|
*
* Scan duration sets how long scanning should be going on, before starting a new scan cycle. 0 means infinite (default).
* Scan window sets how much of the interval should be occupied by scanning. Should be >= BLESCANINTERVAL.
* Scan interval is how long scanning should be done on each channel. BLE uses 3 channels for advertising.
* -> Adjust these values with power consumption in mind if power is limited.
* -> Scan interval can be changed during runtime by remote comammand.
*/

// WiFi scan parameters
#define WIFI_MY_COUNTRY                 "01"    // select 2-letter locale for Wifi RF settings, e.g. "DE"; use "01" for world safe mode
#define	WIFI_CHANNEL_SWITCH_INTERVAL    50      // [seconds/100] -> 0,5 sec.
#define WIFI_CHANNEL_MAP                WIFI_CHANNEL_ALL  // possible values see libpax_api.h

// LoRa payload default parameters
#define MEM_LOW                         2048    // [Bytes] low memory threshold triggering a send cycle
#define RETRANSMIT_RCMD                 5       // [seconds] wait time before retransmitting rcommand results
#define PAYLOAD_BUFFER_SIZE             51      // maximum size of payload block per transmit
#define PAYLOAD_OPENSENSEBOX            1       // send payload compatible to sensebox.de (swap geo position and pax data)
#define LORADRDEFAULT                   5       // 0 .. 15, LoRaWAN datarate, according to regional LoRaWAN specs [default = 5]
#define LORATXPOWDEFAULT                14      // 0 .. 255, LoRaWAN TX power in dBm [default = 14]
#define MAXLORARETRY                    500     // maximum count of TX retries if LoRa busy
#define SEND_QUEUE_SIZE                 10      // maximum number of messages in payload send queue [1 = no queue]

// Hardware settings
#define RGBLUMINOSITY                   30      // RGB LED luminosity [default = 30%]
#define DISPLAYREFRESH_MS               40      // OLED refresh cycle in ms [default = 40] -> 1000/40 = 25 frames per second
#define DISPLAYCONTRAST                 80      // 0 .. 255, OLED display contrast [default = 80]
#define DISPLAYCYCLE                    3       // Auto page flip delay in sec [default = 2] for devices without button
#define HOMECYCLE                       30      // house keeping cycle in seconds [default = 30 secs]

// Settings for BME680 environmental sensor
#define BME_TEMP_OFFSET                 5.0f    // Offset sensor on chip temp <-> ambient temp [default = 5°C]
#define STATE_SAVE_PERIOD               UINT32_C(360 * 60 * 1000) // update every 360 minutes = 4 times a day
#define BMECYCLE                        1       // bme sensor read cycle in seconds [default = 1 secs]

// OTA settings
#define USE_OTA                         0       // set to 0 to disable OTA update
#define WIFI_MAX_TRY                    5       // maximum number of wifi connect attempts for OTA update [default = 20]
#define OTA_MAX_TRY                     5       // maximum number of attempts for OTA download and write to flash [default = 3]
#define OTA_MIN_BATT                    50      // minimum battery level for OTA [percent]
#define RESPONSE_TIMEOUT_MS             60000   // firmware binary server connection timeout [milliseconds]

// settings for syncing time of node with a time source (network / gps / rtc / timeserver)
#define TIME_SYNC_LORAWAN               1       // set to 1 to use LORA network as time source, 0 means off [default = 1]
#define TIME_SYNC_LORASERVER            0       // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
#define TIME_SYNC_INTERVAL              60      // sync time attempt each .. minutes from time source [default = 60], 0 means off
#define TIME_SYNC_INTERVAL_RETRY        10      // retry time sync after lost sync each .. minutes [default = 10], 0 means off
#define TIME_SYNC_SAMPLES               1       // number of time requests for averaging, max. 255
#define TIME_SYNC_CYCLE                 60      // delay between two time samples [seconds]
#define TIME_SYNC_TIMEOUT               400     // timeout waiting for timeserver answer [seconds]
#define TIME_SYNC_COMPILEDATE           0       // set to 1 to use compile date to initialize RTC after power outage [default = 0]
#define TIME_SYNC_TIMEZONE              "UTC" // Timezone in POSIX format (example shows Germany/Berlin)

// Ports on which the device sends and listenes on LoRaWAN and SPI
#define COUNTERPORT                     1       // counts
#define MACPORT                         0       // network commands
#define RCMDPORT                        2       // remote commands
#define STATUSPORT                      2       // remote command results
#define CONFIGPORT                      3       // config query results
#define GPSPORT                         4       // gps - NOTE: set to 1 to send combined GPS+COUNTERPORT payload
#define BUTTONPORT                      5       // button pressed signal
#define RESERVEDPORT                    6       // reserved (unused)
#define BMEPORT                         7       // BME680 sensor
#define BATTPORT                        8       // battery voltage
#define TIMEPORT                        9       // time query and response
#define SENSOR1PORT                     10      // user sensor #1
#define SENSOR2PORT                     11      // user sensor #2
#define SENSOR3PORT                     12      // user sensor #3

// Cayenne LPP Ports, see https://community.mydevices.com/t/cayenne-lpp-2-0/7510
#define CAYENNE_LPP1                    1       // dynamic sensor payload (LPP 1.0)
#define CAYENNE_LPP2                    2       // packed sensor payload (LPP 2.0)
#define CAYENNE_GPS                     3       // full scale GPS payload
#define CAYENNE_ACTUATOR                10	    // actuator commands
#define CAYENNE_DEVICECONFIG            11	    // device period configuration
#define CAYENNE_SENSORREAD              13	    // sensor period configuration
#define CAYENNE_SENSORENABLE            14	    // sensor enable configuration

// MQTT settings, only needed if MQTT is used (#define HAS_MQTT in board hal file)
#define MQTT_ETHERNET 1 // select PHY: set 0 for Wifi, 1 for ethernet (Wifi not yet implemented!)
#define MQTT_INTOPIC "paxin"
#define MQTT_OUTTOPIC "paxout"
#define MQTT_PORT 1883
#define MQTT_SERVER "public.cloud.shiftr.io"
#define MQTT_USER "public"
#define MQTT_PASSWD "public"
#define MQTT_RETRYSEC 20  // retry reconnect every 20 seconds
#define MQTT_KEEPALIVE 10 // keep alive interval in seconds
//#define MQTT_CLIENTNAME "my_paxcounter" // generated by default

Try setting sleep cycle off by setting sleep cycle to 0 in paxcounter.conf. Remember to clear NVRAM before reflashing, otherwise old value will persist. Alternatively, set sleep cycle by rcommand, this takes place immeditaley.

SDS011 needs ~30 seconds warm up time. You must adapt your run/sleep cycle accordingly, by adjusting values for send cycle (time when values are sent), sleep cycle (time while module and SDS011 will sleep) and home cycle (frequency which with values are read from SDS011).

A good starting point to check is SDS011 is working is to switch off sleep mode, as suggested above.

Thanks, I'll give that a go shortly.

Out of interest, is there any documentation on setting up your own OTA server?

I see references to PaxExpress in a few places, and I know that OTA is supported, but the TLS cert for pax.express expired 255 days ago and I'm not sure if Pax.express actually provides OTA or whether it just displays the data?

It would be a lot easier for me to be able to update these devices via OTA rather than serial!

I don't maintain PaxExpress, thus can't answer questions related to this.

The original OTA function was based on Jfrog Bintray, but Jfrog cancelled Bintray as SaaS. PaxExpress took over this role for paxcounter boards, what means it provides an OTA update server which is compatible to Bintray and works with paxcounter code.

Ok, thanks, I'll look into that.

I tried setting sleep to 0 and clearing the NVRAM but I'm still getting the same results so I'll keep playing with the settings and see what I can gt back from them.

The first reading on boot is always reliable though, so at least I know 99.99% of my device is now working as it should!

The sds011 code was from @AugustQu as i remember, maybe he is still reading here?

please give me one day or two, I will look for it.

Amazing, thank you.

Let me know if I can provide any further data to help.

I checked this today, and found a working configuration with these settings:

Board LILYGO® Paxcounter LoRa V2.1_1.6.1

// SDS011 dust sensor settings
#define HAS_SDS011 1 // use SDS011
// used pins on the ESP-side:
#define SDS_TX (12)     // connect to RX on the SDS011
#define SDS_RX (14)     // connect to TX on the SDS011

Note: Disable SD-Card when using GPIO 12/14 for SDS!

Keeping the default settings in paxcounter.conf:

// Payload send cycle and encoding
#define SENDCYCLE                       30      // payload send cycle [seconds/2], 0 .. 255
#define SLEEPCYCLE                      0       // sleep time after a send cycle [seconds/10], 0 .. 65535; 0 means no sleep [default = 0]
#define PAYLOAD_ENCODER                 2       // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed
#define COUNTERMODE                     0       // 0=cyclic, 1=cumulative, 2=cyclic confirmed
#define SYNCWAKEUP                      300     // shifts sleep wakeup to top-of-hour, when +/- X seconds off [0=off]
...
#define HOMECYCLE                       30      // house keeping cycle in seconds [default = 30 secs]

This setup results to PM10/PM25 values sent every minute, while SDS011 is falling asleep between two send cycles:

12:23:25.505 > I (224018) src/sds011read.cpp: SDS011: pm25: 1.20, pm10: 4.00
12:23:25.505 > D (224018) src/sds011read.cpp: SDS011: go to sleep

image

Your cycle configuration is as follows:

  • board is taking SDS011 probe every 30 seconds (HOMECYCLE)
  • After 5 minutes (SENDCYCLE) the value oft last probe is sent
  • Board then sleeps for 100 secs (SLEEPCYCLE)
    It does what you've configured. Not a software issue. Yes, the documentation on SDS is missing / bad.

OK, thanks, so if I wanted to take a measurement every 5 minutes and then go back to sleep in order to save battery, then would the following make sense?

// Payload send cycle and encoding
#define SENDCYCLE                       30      // payload send cycle [seconds/2], 0 .. 255
#define SLEEPCYCLE                      30       // sleep time after a send cycle [seconds/10], 0 .. 65535; 0 means no sleep [default = 0]
#define PAYLOAD_ENCODER                 2       // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed
#define COUNTERMODE                     0       // 0=cyclic, 1=cumulative, 2=cyclic confirmed
#define SYNCWAKEUP                      300     // shifts sleep wakeup to top-of-hour, when +/- X seconds off [0=off]
...
#define HOMECYCLE                       30      // house keeping cycle in seconds [default = 30 secs]

If I've understood you properly, then it would read the sensor every 30 seconds whilst it's awake, send the message after 60 seconds (30 = 60/2), and then sleep for 5 minutes (30 = 300/10)?

Apologies if this is a basic misunderstanding on my part - I'm happy to try and update the docs once I've got my head around this!

sorry. I didn't look into this project for about 3 years so I had to make PIO working again. Then I had to copy the code and start the project. So I still have no working copy here. I'm working on this.

if I remember it correctly:

please check the file SDS011.cpp. It contains a piece of code like this one:
void SDS011::wakeup() {
sds_data->write(0x01);
sds_data->flush();
}

This code works for some devices but not for all (it's too tricky).

So please check your code and let me know.

Thanks @AugustQu I'll do that shortly

@AugustQu - apologies for the delay in replying.

That file does not exist in the version I am currently running (git latest), I only have https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/sds011read.cpp and the code you mention is not in there.

If it helps, this is the serial output:

16:14:55.132 > I (11419) src/lorawan.cpp: LORA send queue created, size 530 Bytes
16:14:55.145 > I (11441) src/lorawan.cpp: Starting LMIC...
16:14:55.145 > I (11442) src/main.cpp: init fine-dust-sensor
16:14:56.162 > I (11957) src/sds011read.cpp: SDS011: Firmware version [year.month.day]: 18.11.16
16:14:56.664 > I (12958) src/main.cpp: Starting Interrupt Handler...
16:14:56.664 > I (12959) src/main.cpp: Starting Timers...
16:14:56.698 > I (12990) src/timekeeper.cpp: Starting time pulse...
16:14:56.698 > I (12990) src/timekeeper.cpp: Timepulse: internal (ESP32 hardware timer)
16:14:57.695 > I (13991) src/main.cpp: Features: DISP LED BATT LORA SDS PACKED TIME
16:14:57.724 > I (14019) src/timesync.cpp: [14.030] Timeserver sync request started, seqNo#47
16:15:02.772 > I (19061) src/lorawan.cpp: DEVaddr: 0x260B1639 | Network ID: 0x000013 | Network Type: 0
16:15:02.772 > I (19062) src/lorawan.cpp: RSSI: 0 | SNR: 7
16:15:02.779 > I (19063) src/lorawan.cpp: Radio parameters: SF7 | BW125 | CR 4/5
16:15:10.051 > I (26336) src/timekeeper.cpp: [26.347] UTC time: 1711728910.000 sec
16:15:10.051 > I (26338) src/lorawan.cpp: 1 byte(s) sent to LORA
16:15:27.738 > I (44022) src/sds011read.cpp: SDS011 Reading
16:15:28.242 > I (44525) src/sds011read.cpp: SDS011: pm25: 141.10, pm10: 1999.90
16:15:54.153 > I (70434) src/lorawan.cpp: 8 byte(s) sent to LORA
16:16:27.738 > I (104022) src/sds011read.cpp: SDS011 Reading
16:16:28.241 > I (104523) src/sds011read.cpp: SDS011: pm25: 0.00, pm10: 0.00
16:16:54.157 > I (130434) src/lorawan.cpp: 8 byte(s) sent to LORA
16:17:27.754 > I (164022) src/sds011read.cpp: SDS011 Reading
16:17:28.257 > I (164523) src/sds011read.cpp: SDS011: pm25: 0.00, pm10: 0.00
16:17:54.174 > I (190434) src/lorawan.cpp: 8 byte(s) sent to LORA
16:18:27.750 > I (224021) src/sds011read.cpp: SDS011 Reading
16:18:28.253 > I (224522) src/sds011read.cpp: SDS011: pm25: 0.00, pm10: 0.00
16:18:54.161 > I (250433) src/lorawan.cpp: 8 byte(s) sent to LORA
16:19:27.751 > I (284022) src/sds011read.cpp: SDS011 Reading
16:19:28.254 > I (284523) src/sds011read.cpp: SDS011: pm25: 0.00, pm10: 0.00

For anyone else who comes across this, the answer is to replace your SDS011 sensor with a new one.

Doing this solved all these probloems.

Best way to confirm that your SDS011 is working is to plug it in to a USB port with the provided adaptor (I'd lost mine so couldn't do this originally!) and then run something like https://github.com/vvidovic/aqi on your laptop to check the values.

A working sensor will return values every few seconds, a broken sensor will not.

Thanks for your note. To me this looks like a firmware issue on SDS011, not a damaged SDS011. Can you read the firmware version and post here? Thanks.

If connected to paxcounter, the SDS011 firmware version is shown in debug log during initialization.

Edit: it's 18.11.16, you showed this in your log above already.

Please check and compare version on your new sensor. Thanks.

Thanks for your note. To me this looks like a firmware issue on SDS011, not a damaged SDS011. Can you read the firmware version and post here? Thanks.

If connected to paxcounter, the SDS011 firmware version is shown in debug log during initialization.

Edit: it's 18.11.16, you showed this in your log above already.

Please check and compare version on your new sensor. Thanks.

New version is running firmware from 2023:

08:04:22.032 > I (11887) src/sds011read.cpp: SDS011: Firmware version [year.month.day]: 23.6.26

I've had a search but can't see a way to update the firmware on the sensors. If that is indeed the issue, then that would mean I can reuse the existing sensors that I have, although the "old" sensors don't work with the python code I posted above whereas the new one does.