Oliv'

I am currently evaluating some solutions to build my home automation system. As a part of this system I want to monitor air quality, but, I do not have any sensor yet, so I use a public service and parse its data with Node-RED.

I built the following flow which gets the data from Air Rhone-Alpes, a local service. After grabbing the web page, it extracts the pollution level, parses it, publishes it to my MQTT broker. I added a filter to avoid any update if there is no change in the pollution level value. Another flow subscribed to the MQTT topic and send ioPush-App notifications depending on the pollution level.

Node-RED screenshot

Node-RED screenshot

The flow may be useful to somebody else to understand how to parse an HTML page, but mainly people from the Rhône-Alpes area, France will use it :)

So copy the following flow, and insert it in your Node-RED page (Import->Clipboard->Paste). It can be tested by clicking on the Start flow button.

[
  {
    "id": "b82a5ab2.47d5a8",
    "type": "mqtt-broker",
    "broker": "localhost",
    "port": "1883",
    "clientid": "Node-RED"
  },
  {
    "id": "9f2c1b12.60d3e8",
    "type": "inject",
    "z": "d99ce1.ff26632",
    "name": "Start flow",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "3600",
    "crontab": "",
    "once": true,
    "x": 138.99993896484375,
    "y": 102.55555311838782,
    "wires": [["e9f3befe.160c4"]]
  },
  {
    "id": "e9f3befe.160c4",
    "type": "http request",
    "z": "d99ce1.ff26632",
    "name": "",
    "method": "GET",
    "ret": "txt",
    "url": "http://www.air-rhonealpes.fr/indice/atmo",
    "x": 218.99993896484375,
    "y": 159.55555311838782,
    "wires": [["30106e06.cfef92"]]
  },
  {
    "id": "30106e06.cfef92",
    "type": "switch",
    "z": "d99ce1.ff26632",
    "name": "Check HTTP status",
    "property": "statusCode",
    "rules": [
      { "t": "eq", "v": 200, "v2": 0 },
      { "t": "neq", "v": 200, "v2": 0 }
    ],
    "checkall": "true",
    "outputs": 2,
    "x": 319.49993896484375,
    "y": 208.8888966242472,
    "wires": [["473dec33.b8c214"], ["4c47b272.b3b84c"]]
  },
  {
    "id": "473dec33.b8c214",
    "type": "function",
    "z": "d99ce1.ff26632",
    "name": "Extract data",
    "func": "var msg = { payload:msg.payload.split(\"<tr class=\\\"odd\\\">\")[3].split(\"span\")[3].substr(24, 1) };\n\nreturn msg;",
    "outputs": "1",
    "noerr": 0,
    "x": 526.4999771118164,
    "y": 176.66666507720947,
    "wires": [["4dfde937.b20218"]]
  },
  {
    "id": "576fcefb.a8903",
    "type": "mqtt out",
    "z": "d99ce1.ff26632",
    "name": "",
    "topic": "/raw/Outside/AirQuality",
    "qos": "0",
    "retain": "false",
    "broker": "b82a5ab2.47d5a8",
    "x": 975.4999771118164,
    "y": 176.66666507720947,
    "wires": []
  },
  {
    "id": "4c47b272.b3b84c",
    "type": "function",
    "z": "d99ce1.ff26632",
    "name": "Add error message",
    "func": "msg.payload = \"Erreur - Impossible de récupérer la polution de Grenoble @\" + msg.url\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "x": 549.4999771118164,
    "y": 236.66666507720947,
    "wires": [["76bea7bc.894158"]]
  },
  {
    "id": "1319a2fc.ece65d",
    "type": "comment",
    "z": "d99ce1.ff26632",
    "name": "Get the data from http://www.air-rhonealpes.fr",
    "info": "1. Every hour, get the RSS feed from \"Air rhone alpes\"\n2. Parse it to find last report URL\n3. Get the report and extract the data",
    "x": 190.5,
    "y": 40,
    "wires": []
  },
  {
    "id": "4dfde937.b20218",
    "type": "rbe",
    "z": "d99ce1.ff26632",
    "name": "Block unless value change",
    "func": "rbe",
    "gap": "",
    "x": 731.5,
    "y": 180,
    "wires": [["576fcefb.a8903"]]
  }
]
comments powered by Disqus