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

[Request] Add AQI sensor #140

Open
Hampo opened this issue Mar 3, 2024 · 13 comments
Open

[Request] Add AQI sensor #140

Hampo opened this issue Mar 3, 2024 · 13 comments

Comments

@Hampo
Copy link

Hampo commented Mar 3, 2024

I have a HP04, and the app shows an AQI value calculated from the 4 sensors (PM2.5, PM10, NO2, VOC). Could this be added to the integration?

@dotvezz
Copy link
Member

dotvezz commented Mar 16, 2024

@Hampo That's a great question! It might be possible, I'll investigate and get back when I have answers.

@Hampo
Copy link
Author

Hampo commented Mar 16, 2024

Thank you :D

@terzo33
Copy link

terzo33 commented Apr 15, 2024

Hi @dotvezz , can you implement AQI sensor?

I have DysonPureHotCoolFormaldehyde

Thanks a lot

@dotvezz
Copy link
Member

dotvezz commented Jul 15, 2024

Hi everyone. Can you please share the models you use (other than @terzo33 who has already done so, of course.

Additionally, there's a tool you can use to help identify the sensors available on your device: (not well-documented yet, that's on my to-do list) called opendyson. If you're willing to help debug this, you can use it to get the values directly from your fan.

You can run opendyson devices to list your devices, find the serial number for the specific device you want to pull information from. Then run opendyson listen YOUR-SERIAL-NUMBER and it will start printing information from your device to the screen. Here's an example below.

$ opendyson devices
Use China region for account? (Default is no) [y/n]: n
Email Address: [email protected]
Code from confirmation email: 123456         
Password: 
Available devices:
- basedevice:
    name: Dyson Fan
    serial: NM7-US-XXXXXXXX
    model: TP02
    type: "475"
    variant: ""
    productCategory: ec
    connectionCategory: wifiOnly
  mqtt:
    password: REDACTED
    username: NM7-US-XXXXXXXX
    root_topic: "475"
    address: 192.168.1.31
  iot:
    endpoint: REDACTED
    client_id: REDACTED
    custom_authorizer_name: REDACTED
    token_key: REDACTED
    token_signature: REDACTED
    token_value: REDACTED
  firmware:
    version: 21.04.03
    auto_update_enabled: false
    new_version_available: false

This is sensitive information that can be used to remotely control your Dyson devices. Please take caution before sharing it with anyone you don't trust.

$ opendyson listen NM7-US-XXXXXXXX
Subscribing to 475/NM7-US-XXXXXXXX/status/current
Subscribing to 475/NM7-US-XXXXXXXX/status/fault
Subscribing to 475/NM7-US-XXXXXXXX/command
Command:  {"msg": "REQUEST-PRODUCT-ENVIRONMENT-CURRENT-SENSOR-DATA", "time": "2024-07-08T16:32:03Z"}
Status:   {"msg":"ENVIRONMENTAL-CURRENT-SENSOR-DATA","time":"2024-07-08T16:32:03.000Z","data":{"tact":"2970","hact":"0052","pact":"0000","vact":"0000","sltm":"OFF"}}
Command:  {"msg": "REQUEST-PRODUCT-ENVIRONMENT-CURRENT-SENSOR-DATA", "time": "2024-07-08T16:32:33Z"}
Status:   {"msg":"ENVIRONMENTAL-CURRENT-SENSOR-DATA","time":"2024-07-08T16:32:33.000Z","data":{"tact":"2970","hact":"0052","pact":"0000","vact":"0000","sltm":"OFF"}}

If you're able to get this to work, please share two things:

  1. The value of your device's firmware version field (maybe there's a firmware-specific quirk to be aware of)
  2. The the output of opendyson listen after letting it run for a while. We can review the values to see if there's something available.

@Hampo
Copy link
Author

Hampo commented Jul 15, 2024

As mentioned in the OP, I have a HP04. Firmware version is ECG2PF.30.06.003.0002, and the logs look like this:

Status:   {"msg":"ENVIRONMENTAL-CURRENT-SENSOR-DATA","time":"2024-07-15T12:24:58.000Z","data":{"tact":"2963","hact":"0054","pm25":"0003","pm10":"0001","va10":"0004","noxl":"0004","p25r":"0003","p10r":"0003","sltm":"OFF"}}
Status:   {"msg":"ENVIRONMENTAL-CURRENT-SENSOR-DATA","time":"2024-07-15T12:25:28.000Z","data":{"tact":"2965","hact":"0053","pm25":"0003","pm10":"0002","va10":"0004","noxl":"0003","p25r":"0003","p10r":"0004","sltm":"OFF"}}

Thanks for looking into this

@dotvezz
Copy link
Member

dotvezz commented Jul 15, 2024

@Hampo thanks! Sorry I missed the HP04 part of your original comment 😅.

Interestingly, there's a thread going on in #159 with TP02/475 devices where the MQTT value labled pact is used for the AQI sensor. Also interestingly, that's actually labeled as a "particulate" value elsewhere. I wonder if this is another example of slightly wrong assumptions when Shen and the original contributors set up the earlier version of this integration. There's more discussion about it in #4 and a bunch of other threads, but basically some of the Home Assistant entities were set up based on slightly wrong (but very close) assumptions about how some of the physical sensors were reporting raw data.

Getting to your HP04, I see the following environment fields in your message (thanks so much for grabbing that for this issue!)

  • tact: currently unused in this integration. Unknown what its meaning is. edit: this is just temperature, and is used in this integration.
    • I'll look into this to see if it's something helpful for us!
  • hact: humidity
  • pm25 and p25r: Particulate Matter (PM2.5)
  • pm10 and p10r: Particulate Matter (PM10)
  • va10: Volatile Organic Compounds
  • noxl: Nitrogen Dioxide
  • sltm: Sleep Timer status

I'll try to find out what tact is, but it's likely that the calculation for AQI is proprietary and happening in the app itself. If that winds up being the case, then this might not be easy to do. Reverse-engineering HTTP and MQTT messages in the MyDyson app has been considerably easier than other things, since there are clearly related landmarks to look for in the decompiled code.

@Hampo
Copy link
Author

Hampo commented Jul 15, 2024

So, according to the APK's source code, tact is meant to be the temperature. My best guess is that it's Kelvin * 10, because 296.5K is 23.35C, which is what my room is.

From the same source, here's all the values:

Code - Type                  - Bounds
tact - Temperature           - 2430-3530
pact - Gen1 Dust             - 0-9
vact - Gen1 VOC              - 0-9
pm25 - PM25                  - 0-149
pm10 - PM10                  - 0-149
va10 - Gen2 VOC              - 0-99
noxl - NO2                   - 0-99
p25r - High Res PM25         - 0-999
p10r - High Res PM10         - 0-999
hact - Humidity              - 0-99
hcho - Formaldehyde          - 0-99
hchr - High Res Formaldehyde - 0-999
co2r - CO2                   - 0-9999

I haven't found the AQI formula offhand, but hopefully these help in the meantime

@dotvezz
Copy link
Member

dotvezz commented Jul 15, 2024

tact is meant to be the temperature . . . Kelvin * 10,

@Hampo Ahhh yep, you're totally right. I must have fat-fingered my code search because it's even being used by this integration.

@pprazzi
Copy link

pprazzi commented Aug 29, 2024

I noticed the same with my Dyson Purifier Hot+Cool Formaldehyde: no AQI sensor.

I'm now looking at another interesting integration for home assistant that just does the calculation : https://github.com/Limych/ha-iaquk

Maybe this can be integrated?

@dotvezz
Copy link
Member

dotvezz commented Aug 29, 2024

@pprazzi interesting... interesting indeed. Looks like that integration uses an index defined here: https://github.com/Limych/ha-iaquk/blob/dev/IAQ_Rating_Index.pdf. I don't really know if that is the same index Dyson uses or not, and unfortunately it looks like the website for the organization isn't around anymore.

But it's something. Maybe I'll just implement that math into an AQI sensor for Dyson devices?

Trying to weigh the pros and cons here. The main con I can think of is possible user confusion if the AQI doesn't match what the app displays.

@pprazzi
Copy link

pprazzi commented Sep 2, 2024

@dotvezz Hi Ben, here's another calculation of an AQI, more specific targeted to Dyson purifiers : https://aarongodfrey.dev/home%20automation/dyson-tp04-integration/

@carpii
Copy link

carpii commented Oct 30, 2024

Here's a (very rough and ready) Jinja template which tries to derive the Air Quality based on the PDF linked earlier
https://github.com/Limych/ha-iaquk/blob/dev/IAQ_Rating_Index.pdf

Obviously its not optimal, but might aid in developing a custom calc

I've scaled down the quality intervals, as were only using a subset of measurements.

It's unclear whether this is directly translatable, since Nitrogen and a few other values are quoted as being an 'index' value. However, they seem to roughly correspond to the range of values in the PDF

The Air Quality it spits out seems to correspond with what the Dyson app is showing (so far, anyway)

The measurements are based on what I can grab from a BP04 - Purifier Big+Quiet Formaldehyde

{% set co2 = states('sensor.dyson_carbon_dioxide') | float %}
{% set temperature = states('sensor.dyson_temperature') | float %}
{% set humidity = states('sensor.dyson_humidity') | float %}
{% set no2_index = states('sensor.dyson_nitrogen_dioxide_index') | float %}
{% set voc_index = states('sensor.dyson_volatile_organic_compounds_index') | float %}
{% set hcho = states('sensor.dyson_hcho') | float %}
{% set pm_2_5 = states('sensor.dyson_pm_2_5') | float %}
{% set pm_10 = states('sensor.dyson_pm_10') | float %}

{% set co2_points = 
5 if co2 <= 600 else 
4 if 601 <= co2 <= 800 else 
3 if 801 <= co2 <= 1500 else 
2 if 1501 <= co2 <= 1800 else 
1 
%}

{% set temperature_points = 
5 if 18 <= temperature <= 21 else 
4 if (17 <= temperature < 18) or (21 < temperature <= 22) else 
3 if (16 <= temperature < 17) or (22 < temperature <= 23) else 
2 if (15 <= temperature < 16) or (23 < temperature <= 24) else 
1 
%}

{% set humidity_points = 
5 if 40 <= humidity <= 60 else 
4 if (30 <= humidity < 40) or (60 < humidity <= 70) else 
3 if (20 <= humidity < 30) or (70 < humidity <= 80) else 
2 if (10 <= humidity < 20) or (80 < humidity <= 90) else 
1 
%}

{% set no2_points = 
5 if no2_index < 0.2 else 
3 if 0.2 <= no2_index <= 0.4 else 
1 
%}

{% set voc_points = 
5 if voc_index < 0.1 else 
4 if 0.1 <= voc_index <= 0.3 else 
3 if 0.3 < voc_index <= 0.5 else 
2 if 0.5 < voc_index <= 1 else 
1 
%}

{% set hcho_points = 
5 if hcho < 0.02 else 
4 if 0.02 <= hcho < 0.05 else 
3 if 0.05 <= hcho < 0.1 else 
2 if 0.1 <= hcho <= 0.2 else 
1 
%}

{% set pm_2_5_points = 
5 if pm_2_5 <= 545 else 
3 if 546 <= pm_2_5 <= 1362 else 
1 
%}

{% set pm_10_points = 
5 if pm_10 <= 68 else 
3 if 69 <= pm_10 <= 170 else 
1 
%}

{% set total_score = co2_points + temperature_points + humidity_points + no2_points + voc_points + hcho_points + pm_2_5_points + pm_10_points %}

{% set air_quality_label = 
"Excellent" if 36 <= total_score <= 40 else 
"Good" if 29 <= total_score <= 35 else 
"Fair" if 22 <= total_score <= 28 else 
"Poor" if 15 <= total_score <= 21 else 
"Inadequate" 
%}

Sensor Points:
- CO2: {{ co2_points }}
- Temperature: {{ temperature_points }}
- Humidity: {{ humidity_points }}
- NO2 Index: {{ no2_points }}
- VOC Index: {{ voc_points }}
- HCHO Index: {{ hcho_points }}
- PM 2.5: {{ pm_2_5_points }}
- PM 10: {{ pm_10_points }}

Air Quality Score: {{ total_score }}
Air Quality:  {{ air_quality_label }}

@carpii
Copy link

carpii commented Oct 30, 2024

If you're able to get this to work, please share two things:

  1. The value of your device's firmware version field (maybe there's a firmware-specific quirk to be aware of)
  2. The the output of opendyson listen after letting it run for a while. We can review the values to see if there's something available.

Not sure if you still need this, but

Device: BP04
Firmware: 0664PF.00.08.005.0002
Log: https://gist.github.com/carpii/3e64066a05731132ffb854b121b9cd5b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants