AirGradient Forum

AirGradient Open Air Max (O-M-1PPST) - No Home Assistant Support - Looking for Workarounds

TL;DR: The new Open Air Max does NOT support Home Assistant integration. AirGradient confirmed this officially. Looking for community workarounds.

Background

I just received my Open Air Max Outdoor Monitor (O-M-1PPST) and was excited to integrate it with Home Assistant like the regular Open Air and ONE models. Unfortunately, AirGradient support confirmed:

“At the moment, the OA Max does not support Home Assistant - only the AirGradient dashboard. At the moment, we are unsure if HA integration will be added at a later date.”

  • Ethan (AirGradient Support)

Potential Workarounds - Need Community Input!

Since the Max has great features (solar, cellular) but no HA support, I’m wondering if anyone has found alternative integration methods:

  1. AirGradient Cloud API
  • Does the Max send data to the same cloud dashboard as other models?
  • Could we use the REST API (Swagger UI) with HA’s REST integration?
  • Has anyone successfully set up cloud API polling for AirGradient devices?
  1. Local JSON Endpoint
  • Regular Open Air models provide local JSON at /measures/current
  • Does the Max have similar local endpoints we could poll?
  • Anyone willing to test http://[max-ip]/measures/current?
  1. MQTT Integration
  • Standard models support MQTT broker configuration
  • Does the Max have MQTT capabilities in the dashboard settings?

Community Questions

If you have an Open Air Max, please help test:

  1. Try accessing http://[your-max-ip]/measures/current - does it return JSON?
  2. Check if MQTT options exist in your AirGradient dashboard
  3. Can you see Max data in the cloud API endpoints?
  4. Has anyone found other workarounds or integration ideas?**

…Posted by someone who definitely didn’t buy the Max without checking HA compatibility first… :sweat_smile:

1 Like

This is going to be interesting. I’m not sure if it also has wifi or if it is cellular only.
If Only cellular, getting it connected to HA will be a challenge to do securely.

If it also can do straight wifi, then it should be possible or maybe ESPHome config in the future, but I don’t have one of these and didn’t know they were shipping them.

It’s cellular only right now. It seems I will need to strip data from the web map. The current issue is that the only Max device I can find on the list has a 9-minute update time compared to 20 seconds for the WiFi variants. I have not opened the box for the new one yet just incase i need to return it for the regular outdoor one.

We discussed a few days ago to add WiFi functionality into the Max dfirmware and will do so in the coming weeks. With the WiFi functionality we could then also have a much higher frequency of sending data, eg once a minute and HA support should be then easy to implement.

@cihad please get in touch with me through our support form and ask the ticket to be assigned to me.

1 Like

The AirGradient cloud API should already have the max included, so this will definitely be a relatively easy way to pull the data in.

@Samuel_AirGradient could you please answer 3) about MQTT support?

1 Like

WiFi Unit Testing: I found a WiFi Outdoor unit near me (North Santa Rosa, Location ID 81861) that updates every 20 seconds. Is this the normal update frequency for WiFi units?

Max Unit Concerns: I found one Max unit in your API (Central Phuket, O-M-1PPST-CE, Location ID 160762) and during testing observed it updated every 9 minutes, compared to the WiFi unit updating every 20 seconds. Is this normal for Max units?

Cellular vs WiFi Question: When I checked your API database (41,148 total units), every single one shows a ‘wifi’ field with signal strength. Since the Max is a new product, do cellular Max units also report a ‘wifi’ field in the API, or should they show differently? I’m trying to find a cellular unit to check update intervals.

Testing Request: Is there a specific Max station ID you could provide that I could test via your API before opening my device? This would help me understand the expected cellular performance.

First User Questions: Am I among the first outdoor Max customers? If so, would it be acceptable for me to open the device for indoor testing with minimal cellular usage, just to verify API update frequency, without affecting my return options?

Core Question: For my monitoring needs, I want approximately 1-minute update intervals. Can you confirm if the expected cellular update frequency for Max units can meet this requirement, or what is the expected interval?
here was my most recent response. It was tested assuming i can only use the web api to access the data. Also my Max is still sealed into the box.

Do you know what the update rate is for cellular?

Don’t worry with using and testing the Max in regards to your return options. We will make sure you will get it running the way you need to, or happy to take it back to in case that doesn’t work out.

2 Likes

Thank you for the incredibly detailed and helpful responses! This clears up many of my questions and actually makes me much more excited about the Max. The upcoming WiFi functionality sounds perfect for my use case!

Just to confirm - yes, I mean taking the Max out of the box, powering it on, and registering it for API testing. Though at this point based on your responses there is little to no chance i would return it. I sent a message to setup a ticket and asked to speak to you.

I have set it up with a station I found that is close to my house in HA and have succesfully integrated it. Let me know if anything I did looks wrong.
Screenshot 2025-06-23 222040
I used the site and calculations to calculate AQI and EPA PM2.5. I plan to use this to take the API data for the MAX and import it into my HA.

# Template sensors with EXACT AirGradient EPA correction formulas and AQI calculation
# AirGradient REST sensor
rest:
  - resource: "https://api.airgradient.com/public/api/v1/world/locations/measures/current"
    scan_interval: 20
    sensor:
      - name: "Santa Rosa Air Data"
        unique_id: "santa_rosa_air_data"
        value_template: >
          {% for station in value_json %}
            {% if station.locationId == ***** %} #add station ID
              {{ station.pm02 }}
            {% endif %}
          {% endfor %}
        unit_of_measurement: "μg/m³"
        device_class: pm25
        json_attributes_path: "$[?(@.locationId==*****)]" # Add station ID
        json_attributes:
          - pm01
          - pm02
          - pm10
          - atmp
          - rhum
          - rco2
          - tvoc
template:
  - sensor:
      - name: "Santa Rosa PM2.5 EPA Corrected"
        unique_id: "santa_rosa_pm25_epa"
        state: >
          {% set AGraw = state_attr('sensor.santa_rosa_air_data', 'pm02') | default(0) | float %}
          {% set RHraw = state_attr('sensor.santa_rosa_air_data', 'rhum') | default(0) | float %}
          {% if AGraw <= 0 %}
            0
          {% elif AGraw <= 20 %}
            {# Band 1: PM2.5 = [0.524 x AGraw] – [0.0862 x RHraw] + 5.75 #}
            {% set corrected = (0.524 * AGraw) - (0.0862 * RHraw) + 5.75 %}
            {{ [corrected, 0] | max | round(1) }}
          {% elif AGraw <= 30 %}
            {# Band 2: PM2.5 = [0.786 x (AGraw/20 - 3/2) + 0.524 x (1 - (AGraw/20 - 3/2))] x AGraw – [0.0862 x RHraw] + 5.75 #}
            {% set factor = AGraw/20 - 1.5 %}
            {% set weight1 = 0.786 * factor %}
            {% set weight2 = 0.524 * (1 - factor) %}
            {% set corrected = (weight1 + weight2) * AGraw - (0.0862 * RHraw) + 5.75 %}
            {{ [corrected, 0] | max | round(1) }}
          {% elif AGraw <= 50 %}
            {# Band 3: PM2.5 = [0.786 x AGraw] – [0.0862 x RHraw] + 5.75 #}
            {% set corrected = (0.786 * AGraw) - (0.0862 * RHraw) + 5.75 %}
            {{ [corrected, 0] | max | round(1) }}
          {% else %}
            {# Band 4: Complex formula for AGraw > 50 #}
            {# PM2.5 = [0.69 x (AGraw/50 – 21/5) + 0.786 x (1 - (AGraw/50 – 21/5))] x AGraw – [0.0862 x RHraw 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 AGraw^2 x (AGraw/50 – 21/5)] #}
            {% set ratio = AGraw/50 - 21/5 %}
            {% set ratio_complement = 1 - ratio %}
            {% set pm_factor = (0.69 * ratio) + (0.786 * ratio_complement) %}
            {% set rh_factor = 0.0862 * RHraw * ratio_complement %}
            {% set constant_factor = (2.966 * ratio) + (5.75 * ratio_complement) %}
            {% set quadratic_factor = 8.84e-4 * (AGraw * AGraw) * ratio %}
            {% set corrected = (pm_factor * AGraw) - rh_factor + constant_factor + quadratic_factor %}
            {{ [corrected, 0] | max | round(1) }}
          {% endif %}
        unit_of_measurement: "μg/m³"
        device_class: pm25
        
      - name: "Santa Rosa CO2"
        unique_id: "santa_rosa_co2"
        state: "{{ state_attr('sensor.santa_rosa_air_data', 'rco2') | default(0) }}"
        unit_of_measurement: "ppm"
        device_class: carbon_dioxide
        
      - name: "Santa Rosa AQI"
        unique_id: "santa_rosa_aqi"
        state: >
          {% set pm25 = states('sensor.santa_rosa_pm2_5_epa_corrected') | default(0) | float %}
          {% if pm25 <= 12.0 %}
            {# Good: 0-50 AQI #}
            {% set aqi = ((50 - 0) / (12.0 - 0.0)) * (pm25 - 0.0) + 0 %}
          {% elif pm25 <= 35.4 %}
            {# Moderate: 51-100 AQI #}
            {% set aqi = ((100 - 51) / (35.4 - 12.1)) * (pm25 - 12.1) + 51 %}
          {% elif pm25 <= 55.4 %}
            {# Unhealthy for Sensitive Groups: 101-150 AQI #}
            {% set aqi = ((150 - 101) / (55.4 - 35.5)) * (pm25 - 35.5) + 101 %}
          {% elif pm25 <= 150.4 %}
            {# Unhealthy: 151-200 AQI #}
            {% set aqi = ((200 - 151) / (150.4 - 55.5)) * (pm25 - 55.5) + 151 %}
          {% elif pm25 <= 250.4 %}
            {# Very Unhealthy: 201-300 AQI #}
            {% set aqi = ((300 - 201) / (250.4 - 150.5)) * (pm25 - 150.5) + 201 %}
          {% elif pm25 <= 350.4 %}
            {# Hazardous: 301-400 AQI #}
            {% set aqi = ((400 - 301) / (350.4 - 250.5)) * (pm25 - 250.5) + 301 %}
          {% else %}
            {# Extreme Hazardous: 401-500 AQI #}
            {% set aqi = ((500 - 401) / (500.4 - 350.5)) * (pm25 - 350.5) + 401 %}
          {% endif %}
          {{ aqi | round(0) }}
        unit_of_measurement: "AQI"
        icon: mdi:air-filter
        
      - name: "Santa Rosa AQI Category"
        unique_id: "santa_rosa_aqi_category"
        state: >
          {% set aqi = states('sensor.santa_rosa_aqi') | default(0) | int %}
          {% if aqi <= 50 %}
            Good
          {% elif aqi <= 100 %}
            Moderate
          {% elif aqi <= 150 %}
            Unhealthy for Sensitive Groups
          {% elif aqi <= 200 %}
            Unhealthy
          {% elif aqi <= 300 %}
            Very Unhealthy
          {% else %}
            Hazardous
          {% endif %}
        icon: >
          {% set aqi = states('sensor.santa_rosa_aqi') | default(0) | int %}
          {% if aqi <= 50 %}
            mdi:emoticon-happy
          {% elif aqi <= 100 %}
            mdi:emoticon-neutral
          {% elif aqi <= 150 %}
            mdi:emoticon-sad
          {% elif aqi <= 200 %}
            mdi:emoticon-dead
          {% elif aqi <= 300 %}
            mdi:biohazard
          {% else %}
            mdi:skull
          {% endif %}

Thank you again

1 Like

Hi Cihad,

From the first time that we develop this monitor, we want to make a battery powered outdoor monitor that can run with very little maintenance, so it could run independently as long as it has sunlight exposure for the solar panel.
To make the MAX monitor integrated natively to something like HA just like our other monitor model, it would change total behavior of the monitor. Because MAX monitor implement sleep cycle to be able to run with only battery for days.
Even though we want to implement wifi capability, it is still do sleep cycle and only send measurements every 9 minutes (it sends multiple measurement from cache all together in 1 transmission). But if we want to implement HA integration natively, we need to add local server feature which in a sense should always be available.

Would be nice to have discussion regarding this!

Update on AirGradient Max HA Integration

I’ve been working on integrating my AirGradient Max with Home Assistant and wanted to share what I’ve learned so far.

What I discovered about the data pattern: The Max sends cached data every 9 minutes as designed, but each transmission contains 3 samples spaced at 3-minute intervals. The API then puts these samples into 5-minute buckets, which creates the timing misalignment I was seeing. So when I was polling the current API randomly, I was only getting whatever sample happened to be in that 5-minute bucket at that moment - missing the other 2 samples from the same 9-minute transmission.

My HA integration approach: I built a Python script that:

  • Polls the historical API every minute (very lightweight)
  • Uses persistent timestamp tracking to only process NEW data
  • Updates existing HA sensors with the most recent sample from each 9-minute transmission

This way I capture all the cellular data when it arrives, rather than randomly sampling the API and missing samples.

Connectivity challenges: I’m still working with support on cellular connectivity. Currently having very few data points reported. AKA one in the last 24 hours.

Response to AirGradient’s feedback: I totally understand the design tradeoffs. The sleep cycle and 9-minute transmission with cached samples makes perfect sense for battery life. My approach works with this design - I’m still capturing all the data from each transmission. Currently very happy with this approach.

I think it’s absolutely critical to support home assistant, even if it’s not local. While I hate cloud polling, support should be added to the native integration.

2 Likes

Not to derail the conversation here, but interested in the Air Max as well, however, definitely would want WiFi vs cellular connectivity. Is there confirmation if the hardware has WiFi capabilities onboard and it’s a matter of a firmware update, or is the current hardware only shipping with cellular chip?

Similarly, are there plans to ship a unit without cellular connectivity and only WiFi for a reduced rate? I’d imagine a good chunk of the nearly $1k price is towards the additional hardware of cellular connectivity + sim + 5yr data plane.

According to the KiCad file, the main chip is ESP32-C6-WROOM-1-N8 which support Wifi and Bluetooth as far as I can tell:
esp32-c6-wroom-1_wroom-1u_datasheet_en.pdf

So it looks like it should be possible. Mine is still on the way so I haven’t had a chance to dig in deep yet, but I hope to work out a basic ESPHome firmware for it, although not all of the new sensors have component support in ESPHome at this time. Also have to figure out how the power management works to keep consumption similarly low.

Assuming the cellular chipset is A7672G and assuming 3KB transmission (idk average payload size since I don’t own the device,), it looks like transmission of data over cellular vs WiFi is almost 30x+ more costly (in terms of power).

Wifi (assuming 802.11n (which should be worst case scenario over 802.11b/g):

Parameter Typical Value
TX current (802.11n) ~200–260 mA @ 3.3V
TX time (3 KB) ~200 ms (0.2 sec)
Light sleep (idle) ~130 µA
Deep sleep (not assumed here) ~20 µA

Energy per 3 KB transmission:
E=I×V×t=0.26 A×3.3 V×0.2 s=0.1716 Ws=0.0000477 Wh

Cellular:

Mode Typical Value
GPRS TX (avg) ~300–350 mA @ 3.8V
TX peak current ~1.6 A (brief bursts)
TX duration (3 KB) ~4–6 seconds typical
Idle (PSM) <10 µA
Idle (network attached) ~5–10 mA

Energy per 3 KB transmission:
E=0.3 A×3.8 V×5 s=5.7 Ws=0.00158 Wh

My goal is to integrate this into WeeWX, so having the data available locally would open up this capability.

From what was described earlier, the cellular radio is only used every 9 minutes, where with Wifi, the expectation would be to use it more frequently if it is expected to work similar to other AirGradient devices, so not sure these are direct apples to apples.

I tried opening the KiCad file for the cellular board but it doesn’t seem to have the actual chip modeled, only the board itself. The Schematic does show A7672G so I think you have the correct chip.