From 7d01c6f23f36d371f2f98b1bfd2a1b480c908274 Mon Sep 17 00:00:00 2001
From: francois <francois@clever.amilab.irit.fr>
Date: Fri, 25 Feb 2022 18:51:17 +0100
Subject: [PATCH] mod IKEA PM sensor with new command

---
 .../libraries/neocampus_drivers/pm_serial.cpp | 11 +++++++--
 tests/ikea_pm2.5/ikea_pm2.5.ino               | 24 ++++++++++++-------
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/neosensor/libraries/neocampus_drivers/pm_serial.cpp b/neosensor/libraries/neocampus_drivers/pm_serial.cpp
index 51487caf..967b944b 100644
--- a/neosensor/libraries/neocampus_drivers/pm_serial.cpp
+++ b/neosensor/libraries/neocampus_drivers/pm_serial.cpp
@@ -8,6 +8,8 @@
 
 	@section  HISTORY
 
+    feb.22  F.thiebolt  IKEA sensor: switched to a new read command borrowed 
+                        from on board IKEA PM sensor micro-controller
     oct.21  F.thiebolt  initial release
 */
 /**************************************************************************/
@@ -868,7 +870,8 @@ boolean pm_serial::_ll_requestRead( void ) {
     res = true;
   }
   else if( _sensor_type ==  pmSensorType_t::IKEA ) {
-    uint8_t command[] = { 0x11, 0x01, 0x02, 0xEC };
+    // uint8_t command[] = { 0x11, 0x01, 0x02, 0xEC }; // regular command
+    uint8_t command[] = { 0x11, 0x02, 0x0b, 0x01, 0xE1 }; // [feb.22] hidden command
     _stream->write(command, sizeof(command)); delay(50);
     res = true;
   }
@@ -1081,7 +1084,7 @@ boolean pm_serial::serialRead_ikea( uint16_t timeout ) {
   uint16_t _frameLen = 0;
   uint16_t _checksum = 0;
   uint16_t _calculatedChecksum = 0;
-  uint8_t _payload[12];
+  uint8_t _payload[16]; // [feb.22] newer command send back up to 16 bytes (no idea DF13-DF16 role)
 
   unsigned long startTime=millis();
 
@@ -1108,10 +1111,13 @@ boolean pm_serial::serialRead_ikea( uint16_t timeout ) {
         break;
 
       case 2:
+        // command byte answer: it could be 0x02 or 0x0b
+        /*
         if( ch != 0x02 ) {
           _index = 0;
           continue;
         }
+        */
         _calculatedChecksum += ch;
         break;
 
@@ -1137,6 +1143,7 @@ boolean pm_serial::serialRead_ikea( uint16_t timeout ) {
           value = makeWord(_payload[10], _payload[11]);   // PM10
           log_debug(F("\n[pm_serial][IKEA] PM10 = "));log_debug(value);log_flush();
           _measures[(uint8_t)ikeaDataIdx_t::PM10]._currentSum += (float)value;
+          // [feb.22] no idea DF13-DF16 bytes from 0x0B command are useful for ??
 
           // data acquired, finisk :)
           log_debug(F("\n[pm_serial][IKEA] "));log_debug(millis()-startTime);
diff --git a/tests/ikea_pm2.5/ikea_pm2.5.ino b/tests/ikea_pm2.5/ikea_pm2.5.ino
index e82a0beb..daf553eb 100644
--- a/tests/ikea_pm2.5/ikea_pm2.5.ino
+++ b/tests/ikea_pm2.5/ikea_pm2.5.ino
@@ -1,5 +1,7 @@
 /* Simple IKEA PM2.5 particle sensor test
  * https://github.com/fu-hsi/PMS
+ * 
+ * [feb.22] new command extracted from IKEA sensor 11 02 0b 01 E1
  */
 
 #include "Arduino.h"
@@ -22,6 +24,7 @@ public:
     uint16_t PM_1_0;
     uint16_t PM_2_5;
     uint16_t PM_10_0;
+    uint16_t PM_UNKNOWN;
   };
 
   PMS(Stream&);
@@ -38,7 +41,7 @@ private:
   enum STATUS { STATUS_WAITING, STATUS_OK };
   enum MODE { MODE_ACTIVE, MODE_PASSIVE };
 
-  uint8_t _payload[12];
+  uint8_t _payload[16];
   Stream* _stream;
   DATA* _data;
   STATUS _status;
@@ -95,9 +98,9 @@ void PMS::passiveMode()
 // Request read in Passive Mode.
 void PMS::requestRead()
 {
-  if (_mode == MODE_PASSIVE)
-  {
-    uint8_t command[] = { 0x11, 0x01, 0x02, 0xEC }; // [PREFIX] [nb_octets] [code_command] [checksum]
+  if (_mode == MODE_PASSIVE) {
+    // uint8_t command[] = { 0x11, 0x01, 0x02, 0xEC }; // [PREFIX] [nb_octets] [code_command] [checksum]
+    uint8_t command[] = { 0x11, 0x02, 0x0b, 0x01, 0xE1 }; // [PREFIX] [nb_octets] [code_command] [checksum]
     _stream->write(command, sizeof(command));
   }
 }
@@ -148,11 +151,13 @@ void PMS::loop()
       break;
 
     case 2:
-      if (ch != 0x02)
-      {
+      // command could be anything like 0x02 or 0x0b
+      /*
+      if (ch != 0x02) {
         _index = 0;
         return;
       }
+      */
       _calculatedChecksum += ch;
       break;
 
@@ -169,6 +174,7 @@ void PMS::loop()
           _data->PM_1_0 = makeWord(_payload[6], _payload[7]);
           _data->PM_2_5 = makeWord(_payload[2], _payload[3]);
           _data->PM_10_0 = makeWord(_payload[10], _payload[11]);
+          _data->PM_UNKNOWN = makeWord(_payload[14], _payload[15]);
         }
 
         _index = 0;
@@ -274,7 +280,7 @@ void setup() {
     Serial.println(F("\n[PM_sensor] request data ..."));Serial.flush();
     delay(250);
     while( Serial2.available() ) {
-      char msg[64];
+      char msg[128];
       char _cur = Serial2.read();
       if( _cur==0x16 ) {
         Serial.print(F("\n[new frame] = "));
@@ -311,8 +317,8 @@ void loop() {
       Serial.print(F("*"));Serial.flush();
     }
     unsigned long _cur = millis();
-    char msg[64];
-    snprintf(msg,sizeof(msg),"[PM_sensor] %lums read [PM1|PM2.5|PM10](µg/m3) %d %d %d", (_cur-_lastActive), data.PM_1_0, data.PM_2_5, data.PM_10_0 );
+    char msg[128];
+    snprintf(msg,sizeof(msg),"[PM_sensor] %lums read [PM1|PM2.5|PM10|PMunknown](µg/m3) %d %d %d %d", (_cur-_lastActive), data.PM_1_0, data.PM_2_5, data.PM_10_0, data.PM_UNKNOWN );
     Serial.println(msg);Serial.flush();
 /*
     Serial.print("\nPM 1.0 (ug/m3): ");
-- 
GitLab