OpenHAB Binding for AirGradient

I have written an AirGradient binding for https://www.openhab.org/ , it is available at AirGradient API Binding - Bundles - openHAB Community

With version 0.3 (just out!) it is starting to become fairly feature complete.

It is fairly easy to install to try it out:

And add a connection to the API

Scanning for Locations will let you find them:

And you can use different types of information for displaying or triggering rules

2 Likes

This binding has now been updated to support local connections to /measures/current (Json) and /metrics (OpenMetrics). Tested on the 3.0.6 beta firmware.

1 Like

Great. Thank you for updating it!

I thought I would share how the AirGradient integration with OpenHAB now works with the latest Beta firmwares.

The adapter is currently on the (free) add-on store. When the beta firmware stabilizes, I will try to get it integrated into the official addons distribution to be bundled with every installation when the beta firmware work start stabilizing.

To install it from the add-on store, you search for “airgradient” and press install.

After you have added the add-on, autodiscovery will kick on. If your devices are on your local network, they will be found and placed in the OpenHAB Inbox.

image

From here you can add it as a thing and give it a name.

Now you have a connection, but we haven’t defined the sensor in OpenHAB. To do that you need to go to Things – Plus – AirGradient Binding – Scan. The sensor will pop up, and you add it and give it a name.

For the sensor you have all the properties, and you can add items in OpenHAB for them, to show them in dashboards (pages in OpenHAB terminology) or use them in automations.

Here I have added temperature and humidity with the default values:

If I use the temperature and humidity widget from Temperature and Humidity Display Widget - UI Widgets - openHAB Community

image

Cloud

For connections to the cloud, you need to add the API manually.

You need a token from AirGradient Connectivity Settings

image

Copy the token from the AirGradient portal, and paste it into the token field when you create the thing on OpenHAB. If you Show Advanced, you can also change the refresh interval to suite you (default 10 minutes).

To discover devices in the cloud, you trigger the same scan as for local devices. To to Things – press the round blue plus - select the AirGradient Binding – Scan

Sensors in the cloud support a couple more features than the local sensors. There is a Calibration channel for triggering Co2 calibration, and there is a LEDs Mode channel for seeing the current LEDs mode and for changing the LEDs mode.

Here is how you can change it from the user interface, but it is also simple to make it prettier on a page with buttons or other controls:

Here is how you could create rules to turn off the LEDs at 22:00, and turn them back to Co2 mode at 08:00.

I love the new beta firmwares and the possibilities they give. The only things I can see missing for feature parity between local and cloud, is the possibility to read and set LED mode locally and to trigger co2 calibrations locally. In addition, for the examples above, I am running my own mDNS setup built on top of the 3.0.7 firmware for autodetection to work. Without them we might need some fixes in some other software.

I believe we will add this functionality soon as we will also need it for the native home assistant integration.

1 Like

Many thanks for working on this integration. I want to mention it in our documentation. Does it also support the outdoor monitor Open Air?

1 Like

Hi, I am testing against a O-1PST running the old firmware and a I-9PSL with latest beta firmware in addition to the variety of devices on the cloud API for a wide coverage. When the beta becomes official I’ll update both of them to that.

Some functionality isn’t supported on the old firmware (local detection and reading values), and some functionality isn’t on the outdoor unit (LEDs), but everything that is supported on the firmware/hardware should work, and if it doesn’t I’ll fix it.

In addition to what is officially supported in the firmware, it does also support prometheus and json locally against third party firmware, in case someone runs on older versions with those enabled.

Feel free to mention it anywhere you want.

1 Like

I’ve just setup my O-1PST outdoor monitor.

I believe that I run the latest firmware 3.0.9, however, I am not sure as I can’t seem to find the firmware version information in the dasshboard anymore.

But assuming I run 3.0.9 on the O-1PST, should I be able to access the outdoor monitor locally? Because scanning in OpenHAB does not discover the outdoor monitor.

Hi, if it isn’t able to autodetect the monitor locally, the reason could be too old firmware, or there could be a bug. (I have tested here with O-1PST and 3.0.8.)

Could you try to add it manually? (E.g use http://192.168.x.x/measures/current for the hostname)

If you add both a bridge and a location in the OpenHAB, the location should have a firmware version property:

Another way, If you are able to show openhab logs and use the console, you could try setting “log:set DEBUG org.openhab.binding.airgradient” and look for version numbers strings like in the log line below:

Got measurements with status 200: {“wifi”:-62,“serialno”:“xxxxxxxx”,“rco2”:447,“tvocIndex”:57,“tvoc_raw”:31852,“noxIndex”:
2,“nox_raw”:0,“atmp”:21.99,“rhum”:33,“boot”:20437,“ledMode”:“off”,“firmwareVersion”:“3.0.6”}(application/json)

Sometimes I don’t get the firmware version:
“model”:“I-9PSL”,“firmwareVersion”:null

so if that is what you see, then the plugin isn’t able to help.

Thanks for your reply.

I’ve verified that the outdoor monitor runs 3.0.9.

Where? The binding lets me select

  • AirGradient API
  • AirGradient Location
    when pressing the ‘+’ button. And It appears “AirGradient Location” requires a prior “AirGradient API” creating a “Bridge”.

That said, yesterday, when I power cycled the montior, OpenHAB suddenly discovered the device. I was even able to add it. However, the AirGradient thing did not show up any channels. So I removed it again.

Believing that the, I assume zeroconf based, discovery only works a brief period after the monitor is powered on, I power cycled it this morning. However, OpenHAB does neither automatically or manually discover the device. :confused:

Not sure if this is related, but I see the following NullPointerException in OpenHAB’s logs:

2024-04-08 00:43:59.414 [ERROR] [y.mdns.internal.MDNSDiscoveryService] - Participant 'org.openhab.binding.airgradient.internal.discovery.AirGradientMDNSDiscoveryParticipant' threw an exception
java.lang.NullPointerException: Cannot invoke "String.matches(String)" because "segment" is null
        at org.openhab.core.common.AbstractUID.validateSegment(AbstractUID.java:99) ~[bundleFile:?]
        at org.openhab.core.common.AbstractUID.<init>(AbstractUID.java:75) ~[bundleFile:?]
        at org.openhab.core.common.AbstractUID.<init>(AbstractUID.java:58) ~[bundleFile:?]
        at org.openhab.core.thing.UID.<init>(UID.java:57) ~[bundleFile:?]
        at org.openhab.core.thing.ThingUID.<init>(ThingUID.java:47) ~[bundleFile:?]
        at org.openhab.binding.airgradient.internal.discovery.AirGradientMDNSDiscoveryParticipant.getThingUID(AirGradientMDNSDiscoveryParticipant.java:126) ~[?:?]
        at org.openhab.core.config.discovery.mdns.internal.MDNSDiscoveryService.removeDiscoveryResult(MDNSDiscoveryService.java:236) [bundleFile:?]
        at org.openhab.core.config.discovery.mdns.internal.MDNSDiscoveryService.serviceRemoved(MDNSDiscoveryService.java:200) [bundleFile:?]
        at javax.jmdns.impl.ListenerStatus$ServiceListenerStatus.serviceRemoved(ListenerStatus.java:81) [bundleFile:3.5.8]
        at javax.jmdns.impl.JmDNSImpl$5.run(JmDNSImpl.java:1343) [bundleFile:3.5.8]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) [?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
        at java.lang.Thread.run(Thread.java:833) [?:?]

and, fwiw:

$ curl -s 192.168.188.44/measures/current | jq
{
  "wifi": -79,
  "serialno": "<redacted>",
  "rco2": 456,
  "pm01": 8,
  "pm02": 12,
  "pm10": 13,
  "pm003Count": 1476,
  "atmp": 17.44,
  "rhum": 70,
  "tvocIndex": 93,
  "tvoc_raw": 32277,
  "noxIndex": 1,
  "nox_raw": 19210,
  "boot": 124,
  "ledMode": "co2",
  "firmwareVersion": "3.0.9",
  "fwMode": "O-1PST"
}

Hi, @Flow, this is great info for me!

There are two levels of autodetect kicking in. One MDNS/zeroconf (which is the one with the exception) which detects sensors in the local network, and another one which detects them if you are connected to the cloud API. The exception you get is from the MDNS discovery, where it fails because it is not able to find a serial number of a thing. Did you see any debug log line (just?) before that for “Getting thing ID for: App”? (This could also be related to the removal of the service)

I have sometimes seen that the MDNS autodiscovery has been slow. I do not know if it is AirGradient announcing the service slowly, or if it is OpenHAB detecting it slowly, but using Linux tools I have seen services being advertised by AirGradient before they are picked up by OpenHAB, so I fear that is a generic OpenHAB problem.

The namings of the thing types in OpenHAB makes more sense for when people connect to the CloudAPI than locally (local connections wasn’t possible when I started). For the cloud API there is one connection to the API and it can have several sensors. For direct connection there is a one-to-one connection. Maybe it would be easier to understand if I added a “LocalSensor” thing - which was either autodetected with MDNS or added manually with a URL?

To set up the connection manually, you must:

  1. Add new thing - Add an AirGradient API on http://192.168.x.x/measures/current (this will be the bridge)
  2. Add new thing - Add an AirGradient Location which uses the API you just created as a Bridge
  3. The AirGradient Location will have the channels you are looking for

Actually, you should be able to - instead of step 2 - Add new Thing - AirGradient Binding - Scan - and Sensor_serialnumber should appear in your inbox.

-J

No, but that could very well be beaucse debug logs are disable. How about creating a non-debug log-level message in case an unexpected or incomplete ServiceInfo is encountered?

I can confirm that using avahi-discover, the _airgradient._tcp MDNS service is responsive and seems to contain all relevant information (model, serialno, fw_ver). Assuming there is no caching or similar involved, we could probably rule out the monitor being slow or sluggish with regard to MDNS announcements.

That said, in my experience MDNS-based discovery works reliable in OpenHAB, which makes we doubt that it is a generic MDNS implementation issue in OpenHAB. But that is just my experience and could very well be wrong.

That sounds like a sensible idea. In fact, I was expecting to see such an entry presented by the binding.

Furthermore, some settings could (and probably should) be different when querying the local API instead of the Airgradient API. For example, the refresh interval could very be less than 10 minutes (600 seconds).

This requires me to specify a token, which I do not have. I’ve tried a dummy string.

This requires me to specify a “Location ID”. I’ve tried a dummy string.

Nope, that did not work.

However, setting up the connection manually using dummy string values allowed me to add the thing.

That said, I only see NULL as value. Here is the debug log:

2024-04-09 09:16:18.474 [DEBUG] [t.internal.AirGradientHandlerFactory] - We support: [airgradient:location, airgradient:airgradientapi]
2024-04-09 09:16:18.485 [DEBUG] [t.internal.AirGradientHandlerFactory] - We support: [airgradient:location, airgradient:airgradientapi]
2024-04-09 09:16:18.488 [DEBUG] [t.internal.AirGradientHandlerFactory] - Creating Bridge Handler for airgradient:airgradientapi
2024-04-09 09:16:18.489 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Getting supported services
2024-04-09 09:16:18.491 [DEBUG] [.AirGradientLocationDiscoveryService] - Constructing discovery service
2024-04-09 09:16:26.420 [DEBUG] [.AirGradientLocationDiscoveryService] - Starting Location discovery for bridge airgradient:airgradientapi:AirGradientLocalOutdoor
2024-04-09 09:17:30.268 [DEBUG] [t.internal.AirGradientHandlerFactory] - We support: [airgradient:location, airgradient:airgradientapi]
2024-04-09 09:17:30.280 [DEBUG] [t.internal.AirGradientHandlerFactory] - We support: [airgradient:location, airgradient:airgradientapi]
2024-04-09 09:17:30.284 [DEBUG] [t.internal.AirGradientHandlerFactory] - Creating Location Handler for airgradient:location
2024-04-09 09:17:59.859 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:18:42.075 [WARN ] [.io.rest.auth.internal.TokenResource] - Not refreshing token for session 21103f99-d4bf-45ed-8456-f62b89e5792d of user flo, missing or invalid session cookie
2024-04-09 09:18:42.077 [WARN ] [.io.rest.auth.internal.TokenResource] - Token issuing failed: invalid_grant
2024-04-09 09:19:49.365 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":470,"pm01":14,"pm02":21,"pm10":21,"pm003Count":2601,"atmp":16.26,"rhum":73,"tvocIndex":99,"tvoc_raw":32355,"noxIndex":5,"nox_raw":19980,"boot":13,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:19:49.368 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.731 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:pm01: REFRESH
2024-04-09 09:21:49.820 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.823 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.838 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:atmp: REFRESH
2024-04-09 09:21:49.845 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:rhum: REFRESH
2024-04-09 09:21:49.848 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:wifi: REFRESH
2024-04-09 09:21:49.849 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:rco2: REFRESH
2024-04-09 09:21:49.860 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:leds: REFRESH
2024-04-09 09:21:49.862 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.861 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:tvoc: REFRESH
2024-04-09 09:21:49.865 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.877 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.879 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.894 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.895 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.902 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:calibration: REFRESH
2024-04-09 09:21:49.910 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:pm02: REFRESH
2024-04-09 09:21:49.914 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.916 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.922 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:pm10: REFRESH
2024-04-09 09:21:49.927 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.929 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.936 [DEBUG] [l.handler.AirGradientLocationHandler] - Channel airgradient:location:AirGradientLocalOutdoor:b94da66c81:pm003Count: REFRESH
2024-04-09 09:21:49.958 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.960 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.976 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-77,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.978 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:49.996 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-78,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:49.998 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:50.014 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-78,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:50.016 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test
2024-04-09 09:21:50.026 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Got measurements with status 200: {"wifi":-78,"serialno":"012345678","rco2":467,"pm01":12,"pm02":19,"pm10":19,"pm003Count":2457,"atmp":16.15,"rhum":73,"tvocIndex":99,"tvoc_raw":32350,"noxIndex":4,"nox_raw":19958,"boot":15,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"} (application/json)
2024-04-09 09:21:50.029 [DEBUG] [ternal.handler.AirGradientAPIHandler] - Could not find measures for location test

I also noticed that it appears that the binding performs one HTTP request per value. It would be great if there where only one request that updates all values.

(splitting up my reply in many posts)

MDNS/OpenHAB:

I flashed my O-1PST with 3.0.9 and deleted all things and items from my development OpenHAB instance.

avahi-browse --all -r

= enp6s0 IPv4 airgradient_12345                      _airgradient._tcp    local
   hostname = [airgradient_12345.local]
   address = [192.168.x.x]
   port = [80]
   txt = ["model=O-1PST" "serialno=12345" "fw_ver=3.0.9" "vendor=AirGradient"]

This looks great. The operating system has (at least a cached) version of the information

I disconnect and reconnect the sensor. Nothing in the inbox.

The first line in createResult(ServiceInfo) is a log line which I have enabled.

I get this:

20:16:05.741 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Discovered airgradient_12345._airgradient._tcp.local. at []: \00 - 
20:16:05.741 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Not able to find URLs for airgradient_12345._airgradient._tcp.local., not autodetecting

So I get autodiscovery information without hostname, which is useless for the purpose.

I press SCAN button on AirGradient binding, it finds a v3.0.8 device, but not the v3.0.9 device. It could be that the v3.0.8 device has been connected for a longer while so disconnect it and connect it some minutes later. Now it fails to find the v3.0.8 device, which is still visible in avahi-browse.

From wireshark, I see MDNS traffic with the information (vendor, fw_ver, serialno and model) included when the device boot up.

When I restart OpenHAB I see a proper detection:

21:12:46.830 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Discovered airgradient_12345._airgradient._tcp.local. at [http://192.168.x.x:80]: \022vendor=AirGradient\014fw_ver=3.0.9\025serialno=12345\014model=O-1PST
21:12:46.831 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Getting thing ID for: App: airgradient Host: [192.168.x.x] Name: airgradient_ecda3b1a2a50 Port: 80 Serial: 12345
21:12:46.831 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Autodiscovered API airgradient_ecda3b1a2a50 with id airgradient:airgradientapi:12345 with host name http://192.168.x.x:80/measures/current. It is a O-1PST

connecting the other device and it is also discovered now, but without the hostname initially:

21:15:41.343 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Discovered airgradient_54321._airgradient._tcp.local. at []: 1airgradient_84fce612e644._airgradient._tcp.local.
21:15:41.344 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Not able to find URLs for airgradient_54321._airgradient._tcp.local., not autodetecting

But then it sends everything, and it is detected:

21:15:41.345 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Discovered airgradient_54321._airgradient._tcp.local. at [http://192.168.x.y:80]: \022vendor=AirGradient\014fw_ver=3.0.6\025serialno=54321\014model=I-9PSL
21:15:41.346 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Getting thing ID for: App: airgradient Host: [192.168.x.y] Name: airgradient_54321 Port: 80 Serial: 54321
21:15:41.347 [DEBUG] [y.AirGradientMDNSDiscoveryParticipant] - Autodiscovered API airgradient_54321 with id airgradient:airgradientapi:54321 with host name http://192.168.x.y:80/measures/current. It is a I-9PSL

Maybe OpenHAB caches things it has tried to autodiscover and since the thing was deleted it doesn’t show it again?

It at least looks like the sensor sends sufficient mDNS information, and it looks like the binding can discover it if it receives such information.

For the stack trace: I found a reproduction when I emptied the inbox, and have added a fix for that.

Adding manually this is what I do:

I add an API with token 123 (should not be required, have fixed but not created a new release of the plugin)
I set the hostname.
I set it to poll every 10 seconds.

I add a location with LocationID 123
I link temp and humidity.
I get null values for linked channels/items, like you have.

I change the location ID to the serialno from the response.

I get data for both channels.

I see 1 call every 10 seconds, which updates both temperature and humidity.

In your logs I see Channel 
 REFRESH. That means that it is the UI which requests an updated value now. I think that explains the extra calls.

Try to change the locationid of the location thing to the serialno of the device.

I’ll be away for a couple of weeks, so don’t expect a quick fix for the “LocalSensor”, but I’ll try to add that when I return.

1 Like

Thank you @Jorgen_Austvik to look into this. In case you think there is anything we can improve on the firmware please let me know.

Maybe one thing people need to be aware. To pull the data from the local network directly, the serial number is the identifier of the monitor. If you use our cloud api, the identifier is the location id which is different from the serial number.

I think the firmware is fine here. I think it is OpenHAB that remembered that you have had an item and deleted it, and then dont let you autodetect the same item again.

And I think my «reuse cloud for local» approach isnt user friendly, so I will make local more distinct

That makes me wonder, is 10 seconds sensible? How often does the monitor update the values?

Yeah, I think that I maybe saw multiple requests because no matching “location” was found.

To answer my own question: Looking at the source code shows that the sensors are updated every 1-5 seconds, so polling every 10 seconds seems sensible.

1 Like

I also think it is very sensible. :+1:

Another suggestion, please change rhum from Double to Integer. I’ve added the “GoogleAssistant” Metadata to the Airgradient Openhab Thing, and reporting humidity requires the item to be Integer. I actually believe that humidity being reported as integer is becoming the de-facto standard.

That said, looking at the JSON return value of the Airgradient:

{"wifi":-68,"serialno":"<redacted>","rco2":404,"pm01":2,"pm02":3,"pm10":3,"pm003Count":723,"atmp":24.41,"rhum":38,"tvocIndex":173,"tvoc_raw":32617,"noxIndex":1,"nox_raw":19538,"boot":3203,"ledMode":"co2","firmwareVersion":"3.0.9","fwMode":"O-1PST"}

I think there are more values that could (and therefore maybe should) be change from Double to Integer:

  • wifi
  • rco2
  • pm1
  • pm2
  • pm10
  • pm003Count
  • tvocIndex
  • noxIndex

Looking at the Airgradient source, it appears that most values are integers there too:

And please consider adding boot to the OpenHAB thing. Unlike its name may suggests, it is actually the number of times the Airgradient has submitted data to the Airgradient API. Ultimately, it is useful to determine when the Airgradient rebooted.

And thank you very much for the OpenHAB binding. :slight_smile:

1 Like