Solved: Airvisual Node Pro Air Quality Monitor Support

I mapped it directly on the filesystem using this HowTo : https://help.ubuntu.com/community/Samba/SambaClientGuide

I created a folder “airvisual” inside /usr/share/hassio/share and mapped it with mount -t cifs command

Then the files are available in /config/airvisual on HA

1 Like

Okay, so I finally got around to doing this and it works pretty well. A couple hints for anyone who wants to do it after me:

  1. Latest versions of Ubuntu do not include CIFS (Samba) mount command by default, you must install it with the commands
apt update
apt install cifs-utils
  1. Airvisual node requires v1 SMB, so make sure you include the argument for it in your fstab entry (mine wouldn’t mount without it). Here’s the syntax I used:
//YOUR_AIRVISUAL_IP/airvisual /usr/share/hassio/config/avnodehome cifs credentials=/etc/avnode.conf,vers=1.0,noexec 0 0

Also, I had no luck getting homeassistant to recognize the folder unless I mounted it using fstab, even if it was mounted correctly. Your mileage may vary, but this is what worked for me. The /etc/avnode.conf file (or whatever filename you want to use) containing the username and password looks like:

username=airvisual
password=YOUR_AIRVISUAL_PASSWORD

If you want to mount your airvisual directory into another folder than your config folder (such as your share folder in the example below), you will need to add this line to your configuration.yaml:

  whitelist_external_dirs:
    - /share
  1. As I like using the AirVisual Card in lovelace, I also made a sensor to use for Air Pollution Level. It looks like this:
  - platform: template
    sensors:
      home_air_pollution:
        friendly_name: "Home Air Pollution Level"
        value_template: >-
          {% if states('sensor.home_air_quality')|float < 50 %}
            Good
          {% elif states('sensor.home_air_quality')|float < 100 and states('sensor.home_air_quality')|float >= 50 %}
            Moderate
          {% elif states('sensor.home_air_quality')|float < 150 and states('sensor.home_air_quality')|float >= 100 %}
            Unh. Sens. Groups
          {% elif states('sensor.home_air_quality')|float < 200 and states('sensor.home_air_quality')|float >= 150 %}
            Unhealthy
          {% elif states('sensor.home_air_quality')|float < 250 and states('sensor.home_air_quality')|float >= 200 %}
            Very Unhealthy
          {% elif states('sensor.home_air_quality')|float < 500 and states('sensor.home_air_quality')|float >= 250 %}
            Hazardous
          {% else %}
            Off the Charts
          {% endif %} 

For the main_pollutant option I just use the one from the nearest public airvisual node, not from my node pro which doesn’t (and can’t) capture this.

Hi all. My wife and I recently bought a Pro Node, so I will be adding official support for it soon. There’s some work that needs to be done first (e.g., https://github.com/home-assistant/home-assistant/pull/32072), but wanted to drop you a line and let you know it’s on the way.

3 Likes

FYI, I’ve submitted a PR to add support for Node/Pro units: https://github.com/home-assistant/core/pull/32815

2 Likes

Cool! Look forward to testing it! TBH the SMB based template sensor is working very well, much better than I ever expected it to, but it will be a lot more practical for people to use a classical integration.

No doubt! The integration will use Samba, as well, but I wouldn’t have gotten the idea for wrapping that into an official integration without the work done here. :pray:t2:

1 Like

Hi @bachya

thanks for the support and development for airvisual ,
on Home Assistant 0.104.3
i sign to airvisual created an api key nothing special ,
follow the documentation i added to configuration file:

airvisual:
  api_key: !secret airvisual_api

getting error:

2020-03-20 23:55:54 ERROR (MainThread) [homeassistant.setup] Setup failed for airvisual: No setup function defined.

any idea?

That configuration schema appeared in 0.107.0; upgrade and it should work.

hi, does it work with Airviusal node pro now? Thank you

Not yet – see above.

Great news ! Thanks for your work <3

1 Like

Thank you for your work!
Just started in HA, so Pro integration will be very helpful

Trying to get Airvisual to work. Homeassistant 0.107.7
Getting the following in the log.
Logger: homeassistant.components.airvisual
Error while retrieving data: city_not_found

On the Airvisual site I can see the calls to the api increment.
Tried with and without geographies: set same result both using a api key
Configuration.yaml

airvisual:
    api_key: 24ecdedd-.........
    # geographies:
    #     city: Bend
    #     state: Oregon
    #     country: USA

When I try the following with my key I get proper results.

 curl --location --request GET 'api.airvisual.com/v2/city?city=Bend&state=Oregon&country=USA&key={24ecdedd-.........}'
{"status":"success","data":{"city":"Bend","state":"Oregon","country":"USA","location":{"type":"Point","coordinates":[-121.312554,44.063916]},"current":{"weather":{"ts":"2020-03-30T22:00:00.000Z","tp":4,"pr":1013,"hu":75,"ws":7.2,"wd":230,"ic":"09d"},"pollution":{"ts":"2020-03-30T22:00:00.000Z","aqius":0,"mainus":"p2","aqicn":0,"maincn":"p2"}}}}

Thanks

Figured it out.
First time I had configured it incorrectly with the wrong city. For some reason when I corrected this it never changed in core.entity_registry
Steps to correct.

  1. Commented out Airvisual: entry, restarted hass.io
  2. removed airvisula entries from core.config_entries and core.entity_registry
  3. un-commented Airvisual: entry and restarted hass.io

Hi bachya, I’m tracking your progress everyday and finally saw ‘Done’ yesterday. This would be crucial for my automations with purifier, based on AQI, and windows opening, based on CO2. Thank you very much for your efforts!

1 Like

Hi @bachya, thanks you again for doing this. Let me please ask if you think this will be introduced next release?

Yes, I anticipate this will go out with 0.110.0.

1 Like

I’ve just updated to Home Assistant 0.110, and followed this guide:

To enable the integration and gather from a Node/Pro unit, add the following lines to your configuration.yaml file:
airvisual:
ip_address: YOUR_NODE_PRO_IP_ADDRESS
password: YOUR_NODE_PRO_SAMBA_PASSWORD

However, I got the error:

Invalid config for [airvisual]: [ip_address] is an invalid option for [airvisual]. Check: airvisual->airvisual->ip_address. (See /config/configuration.yaml, line 36).

Update: I can add the node Pro though Integrations section. Thank you

Hi Aaron,

I’ve moved to a new server and am trying to add my node pros with the official integration now. I got one added, but the second one is not working. I am getting an “unknown error” in the UI and the following traceback in the log:

2020-09-20 22:08:48 INFO (MainThread) [SMB.SMBConnection] Authentication with remote machine "AIRVISUAL" for user "airvisual" will be using NTLM v2 authentication (with extended security)
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] Received SMB message "SMB_COM
_NEGOTIATE" (command:0x72 flags:0x88 flags2:0xC841 TID:0 UID:0)
2020-09-20 22:08:48 INFO (SyncWorker_3) [SMB.SMBConnection] SMB dialect negotiation succes
sful (ExtendedSecurity:True)
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] Received SMB message "SMB_COM
_SESSION_SETUP_ANDX" (command:0x73 flags:0x88 flags2:0xC803 TID:0 UID:62011)
2020-09-20 22:08:48 INFO (SyncWorker_3) [SMB.SMBConnection] Performing NTLMv2 authenticati
on (with extended security) with server challenge "b'7ff2ebeb28d9d94c'"
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] NT challenge response is "<REDACTED>'" (124 bytes)
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] LM challenge response is "<REDACTED>'" (24 bytes)
2020-09-20 22:08:48 INFO (SyncWorker_3) [SMB.SMBConnection] SMB signing deactivated. SMB m
essages will NOT be signed.
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] Received SMB message "SMB_COM
_SESSION_SETUP_ANDX" (command:0x73 flags:0x88 flags2:0xC803 TID:0 UID:62011)
2020-09-20 22:08:48 DEBUG (SyncWorker_3) [SMB.SMBConnection] SMB uid is now 62011
2020-09-20 22:08:48 INFO (SyncWorker_3) [SMB.SMBConnection] Authentication (with extended 
security) successful!
2020-09-20 22:08:48 DEBUG (SyncWorker_2) [SMB.SMBConnection] Received SMB message "SMB_COM
_TREE_CONNECT_ANDX" (command:0x75 flags:0x88 flags2:0xC803 TID:36926 UID:62011)
2020-09-20 22:08:48 DEBUG (SyncWorker_2) [SMB.SMBConnection] Received SMB message "SMB_COM
_OPEN_ANDX" (command:0x2D flags:0x88 flags2:0xC803 TID:36926 UID:62011)
2020-09-20 22:08:48 DEBUG (SyncWorker_2) [SMB.SMBConnection] Received SMB message "SMB_COM
_READ_ANDX" (command:0x2E flags:0x88 flags2:0xC803 TID:36926 UID:62011)
2020-09-20 22:08:48 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web_protocol.py", line 418, in star
t
    resp = await task
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web_middlewares.py", line 119, in i
mpl
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/real_ip.py", line 39, in real
_ip_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/ban.py", line 73, in ban_midd
leware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 127, in auth_m
iddleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 129, in handle
    result = await result
  File "/usr/src/homeassistant/homeassistant/components/config/config_entries.py", line 14
5, in post
    return await super().post(request, flow_id)
  File "/usr/src/homeassistant/homeassistant/components/http/data_validator.py", line 60, 
in wrapper
    result = await method(view, request, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/data_entry_flow.py", line 106, in pos
t
    result = await self._flow_mgr.async_configure(flow_id, data)
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 153, in async_confi
gure
    result = await self._async_handle_step(flow, cur_step["step_id"], user_input)
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 201, in _async_hand
le_step
    result: Dict = await getattr(flow, method)(user_input)
  File "/usr/src/homeassistant/homeassistant/components/airvisual/config_flow.py", line 14
8, in async_step_node_pro
    await client.node.from_samba(
  File "/usr/local/lib/python3.8/site-packages/pyairvisual/node.py", line 284, in from_sam
ba
    data["current"] = await node.async_get_latest_measurements()
  File "/usr/local/lib/python3.8/site-packages/pyairvisual/node.py", line 205, in async_ge
t_latest_measurements
    for pollutant, value in data["measurements"][0].items()
KeyError: 0

Any ideas? Should I open an issue?

It looks like the measurements file that’s being opened up doesn’t have any actual measurements in it.

You can help me debug via pyairvisual:

  1. Clone the latest version of pyairvisual and cd into it:
$ git clone https://github.com/bachya/pyairvisual.git
$ cd pyairvisual/
  1. Set up and activate a Python virtual environment:
$ python3 -m virtualenv .venv
$ source .venv/bin/activate
  1. Initialize the dev environment for pyairvisual:
$ script/setup
  1. Open examples/test_node_pro.py in a text editor and put your Node Pro IP address and password into lines 10-11, respectively:
NODE_PRO_IP_ADDRESS = "<NODE_PRO_IP_ADDRESS>"
NODE_PRO_PASSWORD = "<NODE_PRO_PASSWORD>"
  1. Change the example script to use DEBUG-level logging on line 16:
logging.basicConfig(level=logging.DEBUG)
  1. Save and close the example. Back on the command line, run examples/test_events.py:
$ python3 examples/test_node_pro.py

This will output a lot of info before (hopefully) spitting out the same error you’re seeing here – specifically, it will show me the format of the history data on your unit.

Let me know if you have any questions!

1 Like