airgradienthq / airgradient-homey

Other
1 stars 1 forks source link

Add support for all devices #2

Closed gslender closed 2 months ago

gslender commented 2 months ago

Not sure what of the following are what in terms of features - eg. which of the below are Open Air Outdoor vs Indoor and what is the model name of each??

      8PSL 
      8PSLM 
      8PSL-DE
      I-9PSL
      I-9PSL-DE 
      O-1PP
      O-1PPT
      O-1PS 
      O-1PST 
      O-1DIY
      I-1DIY 

Code currently relies on this logic, but it needs to reflect the full range of models.


  isOpenAirOutdoor(): boolean {
    return this.model.startsWith('O-1PST');
  }

  isONEIndoor(): boolean {
    return this.model.startsWith('I-9PSL');
  }

  isDIY(): boolean {
    return this.model.includes('DIY');
  }

  getModelName(): string {
    if (this.isOpenAirOutdoor()) return 'AirGradient Open Air';
    if (this.isONEIndoor()) return 'AirGradient ONE';
    if (this.isDIY()) return 'AirGradient DIY';
    return 'unknown';
  }
gslender commented 2 months ago

Also, because of this, there is broken logic in the add new devices where I've incorrectly assumed only the O-1PST outdoor model is the only Outdoor model... so I need to be clearly informed of what is the needs of the O-1PST and is that the only special device that has Temp and Humidty Correct values to be chosen/used ??

airgradienthq commented 2 months ago

The following models use a depreciated firmware that does not expose a local server and can not be supported: 8PSL 8PSLM 8PSL-DE

From the model name and model number it should be like this:

Outdoor Monitor Model: Open Air Model Numbers: O-1PST O-1PPT O-1PP O-1PS

P=Plantower PMS5003T=PM Module (PM1,PM2.5,PM10,PM003 Count, Temperature, Humidity) S=Senseair S8= CO2 Module (CO2) T=Sensirion SGP41 = VOC index, NOx index, VOC raw, NOx raw

O-1PPT and O-1PP contain two PMS5003 for enhanced accuracy.

(will continue for indoor monitor).

gslender commented 2 months ago

So the Open Air Outdoor starts with 'O-1P' and any match that starts with that characters would be correctly identified as an Open Air Outdoor Monitor

gslender commented 2 months ago

So if I detect these models, I should warn that they won't connect/work yeah? 8PSL, 8PSLM, 8PSL-D ????

airgradienthq commented 2 months ago

Re older models. (8PSL, 8PSLM, 8PSL) I don't think we can detect them as they don't expose a local server but we can mention in the description of the app that these are not supported.

airgradienthq commented 2 months ago

The "O" in the model number indicates outdoor. The "I" indicates indoor.

gslender commented 2 months ago

So does being Outdoor mean the sensor had those Compensated values as options to choose from?

gslender commented 2 months ago

Also, so DIY means nothing and only the leading O or I is significant??

airgradienthq commented 2 months ago

Indoor Monitor Model: ONE Model Numbers: I-9PSL I-9PSL-DE I-1DIY

They mean: P=Plantower PMS5003=PM Module (PM1,PM2.5,PM10,PM003 Count) S=Senseair S8= CO2 Module (CO2) L=LED Bar of the indoor monitor DE= Display Edition (has small display)

Not mentioned in the model number but all models contain:

gslender commented 2 months ago

I still do not have answers to these questions...

  1. So does being Outdoor mean the sensor had those Compensated values as options to choose from?

  2. Also, so DIY means nothing and only the leading O or I is significant??

airgradienthq commented 2 months ago

It is a bit complicated. For outdoors we need to calibrate the following values:

  1. PM2.5
  2. Temperature
  3. Humidity

However, we recently found out that different batches of the sensor for temperature and humidity behave differently and need different compensation values. We currently implement in the firmware a way to detect the batch. So at the moment no need to implement compensation for temperature and humidity until we figured this out.

For indoors we need to offer compensated values for:

  1. PM2.5

The indoor monitor uses a different sensor for temperature and humidity so there is not the problem like above.

So, I would suggest the following at the moment: Only offer one additional entity called PM2.5 Calibrated for all models (indoor and outdoor).

The formula to calculate the calibrated value is a bit complex:

Correction for PM2.5

This correction formula splits up the algorithms into bands. Note that negative values could result from the formula. In this case, it is recommended to set them to 0.

AGraw = the raw PM2.5 value from the sensor module.

AGraw <30:

PM2.5 = [0.524 x AGraw] – [0.0862 x RH] + 5.75

30≤ AGraw <50:

PM2.5 = [0.786 x (AGraw/20 - 3/2) + 0.524 x (1 - (AGraw/20 - 3/2))] x AGraw – [0.0862 x RH] + 5.75

50 ≤ AGraw <210:

PM2.5 = [0.786 x AGraw] – [0.0862 x RH] + 5.75

210 ≤ AGraw <260:

PM2.5 = [0.69 x (AGraw/50 – 21/5) + 0.786 x (1 - (AGraw/50 – 21/5))] x AGraw – [0.0862 x RH x (1 - (AGraw/50 – 21/5))] + [2.966 x (AGraw/50 –21/5)] + [5.75 x (1 - (AGraw/50 – 21/5))] + [8.84 x (10-4) x AGraw2x (AGraw/50 – 21/5)]

260 ≤ AGraw:

PM2.5 = 2.966 + [0.69 x AGraw] + [8.84 x 10-4 x AGraw2]

airgradienthq commented 2 months ago

2. Also, so DIY means nothing and only the leading O or I is significant??

Yes for now that is a good assumption.

gslender commented 2 months ago

The formula to calculate the calibrated value is a bit complex:

Do you have the formula in C code as per the firmware? It will be easier and less error prone for me to just copy/review that and convert to JS etc

gslender commented 2 months ago

Again, to confirm about the question re temp and humidty compensated values - your API for local contains them. You're saying they are no longer needed or relevant? Correct? So should you not update your API docs to say that and/or deprecate the API to mention that eventually they will be gone/removed?

airgradienthq commented 2 months ago

This should work but not tested yet:

 'pm02': {
    'epa': (raw: number, rhum: number): number => {
      let result = 0;

      if ((raw || raw === 0) && [undefined, null].includes(rhum) ) {
        return raw;
      }
      if (raw < 30) {
        // AGraw <30:
        // PM2.5 = [0.524 x AGraw] – [0.0862 x RH] + 5.75
        result = (0.524 * raw) - (0.0862 * rhum) + 5.75;
      } else if (raw < 50) {
        // 30≤ AGraw <50:
        // PM2.5 = [0.786 x (AGraw/20 - 3/2) + 0.524 x (1 - (AGraw/20 - 3/2))] x AGraw – [0.0862 x RH] + 5.75
        //
        result = (0.786 * (raw/20 - 3/2) + 0.524 * (1 - (raw/20 - 3/2))) * raw - (0.0862 * rhum) + 5.75;
      } else if (raw < 210) {
        // 50 ≤ AGraw <210:
        // PM2.5 = [0.786 x AGraw] – [0.0862 x RH] + 5.75
        //

        result = (0.786 * raw) - (0.0862 * rhum) + 5.75;
      } else  if (raw < 260) {
        // 210 ≤ AGraw <260:
        // PM2.5 = [0.69 x (AGraw/50 – 21/5) + 0.786 x (1 - (AGraw/50 – 21/5))] x AGraw – [0.0862 x RH x (1 - (AGraw/50 – 21/5))] + [2.966 x (AGraw/50 –21/5)] + [5.75 x (1 - (AGraw/50 – 21/5))] + [8.84 x (10-4) x AGraw2x (AGraw/50 – 21/5)]
        //

        result = (0.69 * (raw/50 - 21/5) + 0.786 * (1 - (raw/50 - 21/5))) * raw - (0.0862 * rhum * (1 - (raw/50 - 21/5))) + (2.966 * (raw/50 - 21/5)) + (5.75 * (1 - (raw/50 - 21/5))) + (8.84 * 0.0001 * Math.pow(raw, 2) * (raw/50 - 21/5));
      } else {
        // 260 ≤ AGraw:
        //   PM2.5 = 2.966 + [0.69 x AGraw] + [8.84 x 10-4 x AGraw2]
        result =  2.966 + (0.69 * raw) + (8.84 * 0.0001 * Math.pow(raw, 2));
      }

      return Number(result.toFixed(1));

    }
  },
}
airgradienthq commented 2 months ago

Again, to confirm about the question re temp and humidty compensated values - your API for local contains them. You're saying they are no longer needed or relevant? Correct? So should you not update your API docs to say that and/or deprecate the API to mention that eventually they will be gone/removed?

At the moment it's not clear what is the best way forward but I will add a comment. To be on the safe side we should use the raw values from the local api and not compensated values.

gslender commented 2 months ago

Fixed and updated in current app https://homey.app/a/com.airgradient/test/