AirGradient Forum

Duplicate temperatureUnit key in /config JSON breaks Home Assistant integration

I noticed something strange on one of my AirGradient units today. (For context, I have four AirGradient ONE (I-9PSL-DE) units. I have them all connected to the AirGradient dashboard, as well as added on Home Assistant. I’ve been using them this way for several months.)

One of my units stopped reporting data to Home Assistant. I removed it from Home Assistant under Settings > Devices and attempted re-adding it. When I try to re-add it by IP, it says “Unknown error occurred”. When I take a closer look at the Home Assistant logs, it says:

  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 493, in _async_handle_step
    result: _FlowResultT = await getattr(flow, method)(user_input)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/airgradient/config_flow.py", line 108, in async_step_user
    await self.set_configuration_source()
  File "/usr/src/homeassistant/homeassistant/components/airgradient/config_flow.py", line 41, in set_configuration_source
    config = await self.client.get_config()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/site-packages/airgradient/airgradient.py", line 109, in get_config
    return Config.from_json(response)
           ~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "<string>", line 39, in __mashumaro_from_json__
mashumaro.exceptions.InvalidFieldValue: Field "temperature_unit" of type TemperatureUnit in Config has invalid value None

It appears to be complaining that Temperature Unit field is set to “None.”

So I went and did curl http://[IP]/config on the problem unit and one of the working units:

Problem unit:

{"country":"US","mqttBrokerUrl":"","httpDomain":"","configurationControl":"cloud","pmStandard":"ugm3","temperatureUnit":"f","disableCloudConnection":false,"postDataToAirGradient":true,"ledBarBrightness":100,"displayBrightness":100,"ledBarMode":"co2","tvocLearningOffset":12,"noxLearningOffset":12,"abcDays":8,"model":"I-9PSL-DE","offlineMode":false,"monitorDisplayCompensatedValues":false,"extendedPmMeasures":false,"temperatureUnit":null}%

Working unit:

{"country":"US","mqttBrokerUrl":"","httpDomain":"","configurationControl":"cloud","pmStandard":"ugm3","temperatureUnit":"f","disableCloudConnection":false,"postDataToAirGradient":true,"ledBarBrightness":100,"displayBrightness":30,"ledBarMode":"off","tvocLearningOffset":12,"noxLearningOffset":12,"abcDays":8,"model":"I-9PSL-DE","offlineMode":false,"monitorDisplayCompensatedValues":false,"extendedPmMeasures":false}%

The problem unit includes two entries for temperatureUnit!

Because temperatureUnit appears twice, the second value (null) apparently overwrites the first ("f"). The Home Assistant AirGradient integration’s parser then rejects the config since None is not a valid TemperatureUnit enum value.

The affected unit is running firmware 3.6.2 on model I-9PSL-DE. All four units are on the same firmware. I’m not sure what triggered the duplicate key on only this one unit. I have tried rebooting the unit and the problem persists. Any ideas?

Update: A factory reset of the problem unit seems to have fixed it. After the reset, curl http://[IP]/config returns a proper JSON response with a single temperatureUnit key:

{"country":"US","mqttBrokerUrl":"","httpDomain":"","configurationControl":"local","pmStandard":"ugm3","temperatureUnit":"f","disableCloudConnection":false,"postDataToAirGradient":true,"ledBarBrightness":100,"displayBrightness":100,"ledBarMode":"co2","tvocLearningOffset":12,"noxLearningOffset":12,"abcDays":8,"model":"I-9PSL-DE","offlineMode":false,"monitorDisplayCompensatedValues":false,"extendedPmMeasures":false}% 

I was then able to re-add it to Home Assistant without issue.

So the root cause was definitely something with the device getting into a bad state with the duplicate key. A factory reset clears it, but it’d still be nice to see the firmware avoid producing duplicate JSON keys in the first place :slight_smile: