Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Ikea Vindriktning #4361

Closed
TD-er opened this issue Nov 14, 2022 · 68 comments · Fixed by #4366
Closed

Add support for Ikea Vindriktning #4361

TD-er opened this issue Nov 14, 2022 · 68 comments · Fixed by #4366
Labels
Category: Plugin Related to supported sensors Type: Feature Request Add a completely new feature (e.g. controller/plugin)

Comments

@TD-er TD-er added Category: Plugin Related to supported sensors Type: Feature Request Add a completely new feature (e.g. controller/plugin) labels Nov 14, 2022
@tonhuisman
Copy link
Contributor

Found a link to the datasheet (English content) that also briefly describes the particle data it will return, and the command to send to get it send that data.

@manjh
Copy link

manjh commented Nov 16, 2022

tried to open the datasheet, but "cannot be downloaded safely"...

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

Seems like it is "signed" but not with a commonly known CA.
PM1006_LED_PARTICLE_SENSOR_MODULE_SPECIFICATIONS_printToPDF.pdf

This is the document printed to PDF, so it removes those, including any scripts if they were present.

@manjh
Copy link

manjh commented Nov 16, 2022

Got it.
Another bit of info: while snooping around for datasheets, I noticed that there is a PM1006, but also a PM1006K.
Not sure what the exact difference is.

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

That was also mentioned in the blog.
The IKEA one only reports 2.5 micron particles.

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

Well that's a very extremely limited protocol description in the datasheet:

image

@flashmark
Copy link
Contributor

Hi, I am playing around with ESPeasy for some time and wrote a plugin for the Vindriktning. I am still unsure how to share this plugin. I opened the box and added a Wemos D1. Hooked it up to power and the Tx of the sensor. The Vindriktning CPU is still doing the polling, but the Wemos is snooping the answer.

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

@flashmark Can you share the relevant code here?

@flashmark
Copy link
Contributor

Not sure how to do this. First time using github.

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

copy paste (not too large) chunks of code can be pasted in a message here.
If you prepend it with 3 backticks and also 3 backticks at the end, GitHub will consider it as a code block

@flashmark
Copy link
Contributor

flashmark commented Nov 16, 2022

Main trick, borrowed from others

// Function P240_process_rx
// Handles a single character received from the PM1006 in the Vindrikning
// It expects a response to the poll message sent by the Vindriknings own CPU
// 0x16 <len> <data> <chksum>
// <len>  = size of <data> in char [1 char]
// <data> = message payload, array of <len> chars
// <csum> = checksum, 256-(sum of all received characters) [1 char]
bool P240_process_rx(char c)
{
    switch (rxState) {
    case PM1006_HEADER:
        rxChecksum = c;
        if (c == 0x16) {
            rxState = PM1006_LENGTH;
        }
        break;

    case PM1006_LENGTH:
        rxChecksum += c;
        if (c <= bufferSize) {
            _rxlen = c;
            _index = 0;
            rxState = (_rxlen > 0) ? PM1006_DATA : PM1006_CHECK;
        } else {
            rxState = PM1006_HEADER;
        }
        break;

    case PM1006_DATA:
        rxChecksum += c;
        serialRxBuffer[_index++] = c;
        if (_index == _rxlen) {
            rxState = PM1006_CHECK;
        }
        break;

    case PM1006_CHECK:
        rxChecksum += c;
        rxState = PM1006_HEADER;
#ifdef PLUGIN_240_DEBUG
        P240_dump();
#endif
        return ((rxChecksum&0xFF) == 0);

    default:
        rxState = PM1006_HEADER;
        break;
    }
    return false;
}

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

Backticks are these: `
You're using slashes.

@flashmark
Copy link
Contributor

flashmark commented Nov 16, 2022

I am using a simple state machine as parser of the incoming characters. Characters are gathered "ten per second'

typedef enum {
    PM1006_HEADER,
    PM1006_LENGTH,
    PM1006_DATA,
    PM1006_CHECK
} pm1006_state_t;

And some global storage

// Global variables TODO: attach them to the task to allow multiple instances
  ESPeasySerial *easySerial = nullptr;
  const int bufferSize = 20;
  char serialRxBuffer[bufferSize];
  char debugBuffer[3*bufferSize];
  int rxBufferPtr = 0;
  int rxChecksum = 0;
  int _index = 0;
  int _rxlen = 0;
  int pm25 = 0;
  pm1006_state_t rxState = PM1006_HEADER;

@flashmark
Copy link
Contributor

Plugin is around 375 lines of code, half of it comment. Main issue to move the global variables in something that is bound to the plugin instance. The sensor is working, but a bit boring at my home with only high rates when you fool it with burning matches. I should try to upload it to my github clone

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

I took the liberty to edit your posts to show the correct backticks.
If you press edit on your posts, you can see it.

@flashmark
Copy link
Contributor

Thanks, learned new tricks today :-) Next is to share the code through github. I took the free P240, used the template and reverse engineered serial link sensors like MHZ19.

@tonhuisman
Copy link
Contributor

tonhuisman commented Nov 16, 2022

We have a Developers guide, here

Part of those steps you have already done, like forking the ESPEasy repo.

@flashmark
Copy link
Contributor

Missing part:

 case PLUGIN_TEN_PER_SECOND:
    {
      // code to be executed 10 times per second. Tasks which require fast response can be added here
      // be careful on what is added here. Heavy processing will result in slowing the module down!
      bool new_data = false;
      while ((easySerial->available() > 0) && !new_data) 
      {
        new_data = P240_process_rx(easySerial->read());
        if (new_data) 
        {
          pm25 = float((serialRxBuffer[3] << 8) + serialRxBuffer[4]);
          String log = F("P240 : Data ");
          log += pm25;
          addLogMove(LOG_LEVEL_INFO, log);
        }
      }
      success = true;
    }

@flashmark
Copy link
Contributor

@tonhuisman Will pick it up coming days.

@TD-er
Copy link
Member Author

TD-er commented Nov 16, 2022

Missing part:

 case PLUGIN_TEN_PER_SECOND:
    {
      ...
      success = true;
    }

I think you're also missing a break; statement here.. (it might have been just the next line after the } )

@flashmark
Copy link
Contributor

Thanks, break was missing, but not affecting the functionality. Tried a pull request first time, not sure the code fulfills all requirements. I don't have reviewers at home.

@fly74
Copy link

fly74 commented Nov 17, 2022

I'm interested too to use the Vindriktning :)

@manjh
Copy link

manjh commented Nov 17, 2022 via email

@uzi18
Copy link
Contributor

uzi18 commented Nov 18, 2022

@TD-er PM1006K :
obraz

@TD-er
Copy link
Member Author

TD-er commented Nov 18, 2022

Thanks. It shows at least it shares its protocol with the PM1006.
So I guess we can make the plugin also support the PM1006K and make a selector indicating which values we need to use.

@flashmark
Copy link
Contributor

Note that the plugin I wrote is dedicated to the Ikea Vindriktning. The original Ikea CPU is talking to the sensor and driving the three LEDs. The plugin is listening only to the answers of the sensor and translates them to ESPeasy plugin values. If you wish to take control the Ikea CPU shall be removed and the plugin also has to send queries the sensor. I think this is easily possible as long as the protocol is indeed as given above.

@fly74
Copy link

fly74 commented Nov 20, 2022

@fly74
Copy link

fly74 commented Nov 24, 2022

Is there an action build for testing ?

@fly74
Copy link

fly74 commented Nov 28, 2022

@tonhuisman @flashmark @TD-er Hey not bad a for a first try!

Screenshot 2022-11-28 085827

@fly74
Copy link

fly74 commented Nov 30, 2022

ESP_Easy_mega_20221128_collection_E_ESP32_4M316k works with ESP32 but not ESP_Easy_mega_20221128_collection_E_ESP8266_4M1M with ESP8266 - value is zero all the time

@TD-er
Copy link
Member Author

TD-er commented Nov 30, 2022

What serial port do you use on ESP8266?
Is "use serial" disabled on the tools->Advanced page when using Serial0 or Serial0_swapped ?

@fly74
Copy link

fly74 commented Nov 30, 2022

Physically REST -> D4

and

Screenshot 2022-11-30 145754
Screenshot 2022-11-30 145840

@TD-er
Copy link
Member Author

TD-er commented Nov 30, 2022

Serial1 on ESP8266 is useless.
It can only send, not receive.
It also shows it in the description, "- <- TX" means the TX of the sensor is not connected to anything on the ESP
"GPIO-2 -> RX" means GPIO-2 on the ESP is connected to RX of the sensor.

It is read from left to right, from the viewpoint of the ESP.

@fly74
Copy link

fly74 commented Nov 30, 2022

@TD-er
Copy link
Member Author

TD-er commented Nov 30, 2022

You selected "HW Serial1"
The ESP8266 does have 2 HW serial ports:

  • Serial 0 => RX & TX
  • Serial 1 => TX only

This means HW serial1 on ESP8266 is utterly useless. (well, maybe for outputting logs it may be useful...)

HW Serial0 is default on GPIO 1 & 3 (I will not name the D-notation as I always have to check it as it makes no sense, even though boards like NodeMCU and Wemos D1 mini use it on their silk screen)
However, it is possible to re-assign pins GPIO 13 and 15 (no idea about their D-name equivalent)
This mode is called "HW Serial 0 Swapped" in ESPEasy.
N.B. GPIO 15 is a 'special' pin, so in order to use it for serial, you need to add a PNP transistor.

This means that if you want to connect the sensor to pins other than GPIO 1 & 3, you should select "SW Serial" and pick the right pins.

@fly74
Copy link

fly74 commented Dec 1, 2022

@TD-er Hi Gijs, it's a little tricky and work now with:

Screenshot 2022-12-01 070131
Screenshot 2022-12-01 070228

But why the device must be set GPIO<TX and the devicelist shows it as RX: GPIO-4 (D2)?

@TD-er
Copy link
Member Author

TD-er commented Dec 1, 2022

I tried to make it as unambiguous as possible, so please tell me where it is inconsistent?
The labels have to be read from left to right, where on the left is the ESP related part and on the right the attached sensor.
Thus GPIO (ESP side) <- RX (sensor side)

Only thing I can think of for serial is to change the label into "GPIO (RX) <- TX"
The idea is, you're configuring it from the ESP's viewpoint.
So you need to define the GPIO and connected to it is some pin on the sensor side which happens to be "sending data" which we call TX.
What matters is that the ESP considers it as an RX port.

@fly74
Copy link

fly74 commented Dec 1, 2022

I can live with it. But for me it would be the clearest to set an "GPIO (#) <- REST Pin Sensor". But don't let us splitting hairs :)

@fly74
Copy link

fly74 commented Dec 1, 2022

I made a clip for fixing the ESP inside, if anyone is interested and able to print 3D.

ESP Clip

IMG_3282

@fly74
Copy link

fly74 commented Dec 1, 2022

Another Question the values are only shown if the plugin interval is set less than 10 seconds. I'm using the generic http controller to push values to a database usually every 300 seconds. Can I use a rule to push values every 300s even if the sensor is getting it every 10s?

@TD-er
Copy link
Member Author

TD-er commented Dec 1, 2022

Hmm that sounds like a bug...
Anyway, what you can do to overcome this issue is to copy the value to a dummy task and then call taskrun on that dummy task (you need to assign the controller to the dummy task of course)

@fly74
Copy link

fly74 commented Dec 1, 2022

Hmm that sounds like a bug... Anyway, what you can do to overcome this issue is to copy the value to a dummy task and then call taskrun on that dummy task (you need to assign the controller to the dummy task of course)

Works great. THX.

@fly74
Copy link

fly74 commented Dec 2, 2022

Here the LED values from the instruction manual

20221202_192746

And it was for me better to connect the fan to the 3.3V ESP instead the 5V from the original board. The original connect turn on the fan every ca. 30s. It was annoying, so lower rpm with constant fan is very quiet without loss of accuracy.

@TD-er
Copy link
Member Author

TD-er commented Dec 2, 2022

so lower rpm with constant fan is very quiet without loss of accuracy.

That does really surprise me.
I would expect that lower air flow would result in lower reported values for the dust particle count.
Also when the fan at some point will be a bit more dirty or worn down, it may need more power to start spinning. At 3V3 this may not be possible and then the fan will no longer spin up.

@fly74
Copy link

fly74 commented Dec 2, 2022

I will have an eye on it, but the constant rpm change is annoying to me.

@TD-er
Copy link
Member Author

TD-er commented Dec 2, 2022

Maybe you can also experiment with its orientation? If the fan is slightly tilted, maybe the fan noise is less annoying?

@fly74
Copy link

fly74 commented Dec 2, 2022

The annoying thing the constant spin up and spin down from the measure cycle.

@TD-er
Copy link
Member Author

TD-er commented Dec 2, 2022

Yep, I understand.
But parts of such noise can also be amplified when the fan isn't rolling optimal.
Thus tilting the fan/sensor slightly can maybe also reduce this noise.

@fly74
Copy link

fly74 commented Dec 2, 2022

I bought 2 of them and it's the same for both.

@fly74
Copy link

fly74 commented Mar 23, 2023

@TD-er is it going to official build?

@tonhuisman
Copy link
Contributor

Now that it's merged it will be included in the next Release 😃

@TD-er
Copy link
Member Author

TD-er commented Mar 23, 2023

Yep, but not yet a new build right now.
It is now merged into the mega branch for the next build.

@fly74
Copy link

fly74 commented Mar 24, 2023

Wich builds will include the plugin? Only the collection_E?

@TD-er
Copy link
Member Author

TD-er commented Mar 24, 2023

Wich builds will include the plugin? Only the collection_E?

Also the "climate" and "max" builds.

@andibaciu
Copy link
Contributor

andibaciu commented May 4, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Plugin Related to supported sensors Type: Feature Request Add a completely new feature (e.g. controller/plugin)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants