esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
290 stars 34 forks source link

mics_4514 sensor reading way off #6106

Closed erkr closed 2 weeks ago

erkr commented 1 month ago

The problem

I noticed that the sensor readings for the mics_4514 are way off. The current code two issues: Low concentrations are ignored, higher values are calculated wrong.

Here is the graph for the datasheet for the RED sensor (the OX based sensors have the same issue):

image

I marked the thresholds used in code for the various sensors with colored dots. Two issues for each sensor:

Which version of ESPHome has the issue?

Firmware: 2024.6.6 (Jul 8 2024, 07:53:53)

What type of installation are you using?

Home Assistant Add-on

Which version of Home Assistant has the issue?

core 2024.7

What platform are you using?

mics_4514

Board

ESP32-C3 (Apollo Air-1 device)

Component causing the issue

mics_4514

Example YAML snippet

n/a the issue is in the component code itself. Here a code snippet of the component.

image (https://github.com/esphome/esphome/blob/3920029aff9dd85fd5f0775945b8426c03da471c/esphome/components/mics_4514/mics_4514.cpp#L71-L80)

Anything in the logs that might be useful for us?

N/A

Additional information

No response

erkr commented 1 month ago

Update; I was able to determine the right math for calculating the CO value by mapping points from the datasheet onto a double log graph and find a matching function (see here). Pseudo code for the CO calculation should be:

if (red_f > 3.4f) {
 CO = 0.0;
}
else if (red_f < 0.01) {
  CO = 1000.0;
}
else {
  CO = 4.2/ pow(red_f,1.2);
}

I will determine the other sensors as well

erkr commented 1 month ago

Ammonia (here):

if (red_f > 0.98f) {
 Ammonia = 0.0;
}
else if (red_f < 0.2532) {
  Ammonia = 0.0;  // outside the ammonia range->unlikely
}
else {
  Ammonia = 0.9/ pow(red_f,4.6);
}
erkr commented 1 month ago

Methane (here):

if (red_f > 0.9f) {
 Methane = 0.0;
}
else if (red_f < 0.5) {
  Methane = 0.0;  // outside the range->unlikely
}
else {
  Methane = 630/ pow(red_f,4.4);
}
erkr commented 1 month ago

Ethanol (here):

if (red_f > 1.0f) {
  Ethanol = 0.0;
}
else if (red_f < 0.02) {
  Ethanol = 0.0; // outside the range->unlikely
}
else {
  Ethanol = 1.52/ pow(red_f,1.55);
}

Note: unsure about the range. The ethanol line starts around 1ppm, spec mentions 10-500ppm. I took above 1ppm

erkr commented 1 month ago

H2 (here):

if (red_f > 0.9f) {
  H2 = 0.0;
}
else if (red_f < 0.02) {
  H2 = 0.0; // outside the range->unlikely
}
else {
  H2 = 0.85/ pow(red_f,1.75);
}
erkr commented 1 month ago

Last but not least. NO2 on the OX sensor (here):

if (ox_f < 0.3f) {
  NO2 = 0.0;
}
else {
  NO2 = 0.164 * pow(0x_f,0.975);
}

This sensor is almost linear. The original formula is close. Mainly the original threshold (1.1) is way too high, so it only will register concentrations above 0.15ppm. That should start at 0.05ppm (threshold 0.3)

TrevorSchirmer commented 1 month ago

Update; I was able to determine the right math for calculating the CO value by mapping points from the datasheet onto a double log graph and find a matching function (see here). Pseudo code for the CO calculation should be:

if (red_f > 3.4f) {
 CO = 0.0;
}
else if (red_f < 0.01) {
  CO = 1000.0;
}
else {
  CO = 4.2/ pow(red_f,1.2);
}

I will determine the other sensors as well

Working on a PR for this. Are they by chance backwards in some? CO example below

if (red_f > 3.4f) {
 CO = 0.0; // Should be 1000.0
}
else if (red_f < 0.01) {
  CO = 1000.0; // Should be 0
}
else {
  CO = 4.2/ pow(red_f,1.2);
}
erkr commented 1 month ago

Thanks for working on this🥳

Working on a PR for this. Are they by chance backwards in some? CO example below

No, I believe I got that right. Note in the graph the relation sensor readout of RED vs CO is negative. So smaller readouts are higher CO values. A readout of 3.4 represents the top left of the CO curve (1ppm), 0.01 represents the bottom right 1000ppm

erkr commented 1 month ago

Small remark. This formula:

CO = 4.2 / pow(red_f,1.2);

It's mathematically equal to:

CO = 4.2 * pow(red_f,-1.2);

Note the minus sign in pow(). Whatever you prefer☺️

TrevorSchirmer commented 1 month ago

Created a PR that matches. Mind taking a look @erkr

https://github.com/esphome/esphome/pull/7173

erkr commented 1 month ago

Looks great. How does the process work? Will this be a dev version that we can test before realising it to the public?

jesserockz commented 1 month ago

Looks great. How does the process work? Will this be a dev version that we can test before realising it to the public?

You can test the PR using External Components

Please confirm on the PR itself once tested.