Peter MaMica WongEthan Fan
Published © LGPL

Smart City Air Monitor

Using vehicles to monitor the air quality throughout the city in real time.

AdvancedWork in progress10 hours2,398

Things used in this project

Hardware components

AT&T Starter Kit
×1

Software apps and online services

AT&T Flow
AT&T Flow
AT&T M2X
AT&T M2X
AT&T Drive
PubNub Publish/Subscribe API
PubNub Publish/Subscribe API
Watson
IBM Watson

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Air Monitor

This is the top cover for the air monitor

Air Monitor Bottom

This is the Bottom that will be holding the AT&T Starter Kits and the components

Schematics

AT&T Starter Kit Board

Using this board along with Air Quality Sensor and GPS

Code

ATT Flow

JSON
ATT Flow code for Smart City Air Monitor
[
  {
    "type": "tab",
    "id": "828b2334.7d74e",
    "label": "Data"
  },
  {
    "type": "tab",
    "id": "dca3a3aa.29d59",
    "label": "Registration"
  },
  {
    "type": "tab",
    "id": "ff4604e.3bd1ef8",
    "label": "Virtual Device"
  },
  {
    "type": "tab",
    "id": "2a0a0053.68754",
    "label": "Trigger"
  },
  {
    "type": "tab",
    "id": "edd8f490.1384b8",
    "label": "Flow 1"
  },
  {
    "id": "d012b668.0e6b48",
    "type": "subflow",
    "name": "VirtualData",
    "info": "",
    "in": [
      {
        "x": 78,
        "y": 103,
        "wires": [
          {
            "id": "c25b483b.073eb8"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 413,
        "y": 98,
        "wires": [
          {
            "id": "c25b483b.073eb8",
            "port": 0
          }
        ]
      }
    ]
  },
  {
    "id": "d6754866.b25de8",
    "type": "subflow",
    "name": "Get M2X Device",
    "info": "",
    "in": [
      {
        "x": 64,
        "y": 101,
        "wires": [
          {
            "id": "8832b00b.f292c"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 718,
        "y": 112,
        "wires": [
          {
            "id": "abbf1662.c240f8",
            "port": 0
          }
        ]
      }
    ]
  },
  {
    "id": "3a19c365.ec522c",
    "type": "subflow",
    "name": "Register Check",
    "info": "",
    "in": [
      {
        "x": 46,
        "y": 79,
        "wires": [
          {
            "id": "d5b80e23.d7aec"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 1035.999984741211,
        "y": 75,
        "wires": [
          {
            "id": "f3ee5b81.0e4cc8",
            "port": 0
          },
          {
            "id": "259d311c.16b58e",
            "port": 0
          }
        ]
      },
      {
        "x": 186.99998474121094,
        "y": 294.0000228881836,
        "wires": [
          {
            "id": "aafe8d98.1fd0a",
            "port": 1
          }
        ]
      }
    ]
  },
  {
    "id": "146e5987.6ab216",
    "type": "subflow",
    "name": "CC Auth Encode",
    "info": "",
    "in": [
      {
        "x": 103.74999809265137,
        "y": 110.00000381469727,
        "wires": [
          {
            "id": "5fc7b6a7.ad5a48"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 539.9999885559082,
        "y": 108.75000381469727,
        "wires": [
          {
            "id": "46f42f02.48344",
            "port": 0
          }
        ]
      }
    ]
  },
  {
    "id": "7ddfd805.46bfe8",
    "type": "subflow",
    "name": "Parse Key-Value Pairs",
    "info": "",
    "in": [
      {
        "x": 202.22221851348877,
        "y": 126.6666612625122,
        "wires": [
          {
            "id": "bda6b0b0.4ea2c"
          }
        ]
      }
    ],
    "out": [
      {
        "x": 532.222204208374,
        "y": 130.00000190734863,
        "wires": [
          {
            "id": "bda6b0b0.4ea2c",
            "port": 0
          }
        ]
      }
    ]
  },
  {
    "id": "68544f62.97abb",
    "type": "flow server",
    "hosted": true,
    "name": "flow",
    "flowFile": "flow.json",
    "configFile": "config.json"
  },
  {
    "id": "fa6df2fa.69e0b",
    "type": "m2x feed",
    "z": "edd8f490.1384b8",
    "apiKey": "",
    "name": "my account"
  },
  {
    "id": "843b5498.319c9",
    "type": "http in",
    "z": "828b2334.7d74e",
    "name": "Climate POST",
    "url": "/climate",
    "method": "post",
    "configKey": "",
    "authType": "noAuth",
    "useAuth": false,
    "useOauth": false,
    "encryption": "none",
    "realm": "",
    "site": "",
    "authorizationPath": "/oauth/authorize",
    "tokenPath": "/oauth/access_token",
    "scope": "",
    "encryptObj": [
      "username",
      "password",
      "clientId",
      "clientSecret"
    ],
    "swaggerDoc": "",
    "x": 107.3499755859375,
    "y": 245.60002517700195,
    "wires": [
      [
        "cb554451.c15e18",
        "aadd913e.ba58b8"
      ]
    ]
  },
  {
    "id": "aadd913e.ba58b8",
    "type": "function",
    "z": "828b2334.7d74e",
    "name": "Calculate Heat Index",
    "func": "msg.payload.tempF = msg.payload.temp * 1.8 + 32;\n\nvar HI;\nvar T = msg.payload.tempF;\nvar RH = msg.payload.humidity;\n\nvar t2=Math.pow(T, 2);\nvar t3=Math.pow(T, 3);\nvar rh2=Math.pow(RH, 2);\nvar rh3=Math.pow(RH, 3);\n\n//less accurate formula (var index=-42.379 + 2.04901523*t + 10.14333127*r - 0.22475541*t*r - 6.83783e-03*t2 - 5.481717e-02*rh2 + 1.22874e-03*t2*r + 8.5282e-04*t*rh2 - 1.99e-06*t2*rh2;)\nvar HI =16.923+0.185212*T+5.37941*RH-0.100254*T*RH+0.941695e-2*t2+0.728898e-2*rh2+0.345372e-3*t2*RH-0.814971e-3*T*rh2+0.102102e-4*t2*rh2-0.38646e-4*t3+0.291583e-4*rh3+0.142721e-5*t3*RH+0.197483e-6*T*rh3-0.218429e-7*t3*rh2+ 0.843296e-9*t2*rh3-0.481975e-10*t3*rh3;\n\nHI = Math.round(HI*100)/100;\n\nmsg.payload.heatIndexF = HI;\nmsg.payload.heatIndex = (T - 32) / 1.8;\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 539.2000732421875,
    "y": 337.20001220703125,
    "wires": [
      [
        "4ddb6902.4d65e8",
        "4da56a78.d88c04"
      ]
    ]
  },
  {
    "id": "f2ba835d.f15d8",
    "type": "udp in",
    "z": "828b2334.7d74e",
    "name": "Cimate",
    "iface": "",
    "port": 3000,
    "ipv": "udp4",
    "multicast": "false",
    "group": "",
    "datatype": "buffer",
    "x": 90.01663208007812,
    "y": 440.19997145217144,
    "wires": [
      [
        "c69b666b.6ee328"
      ]
    ]
  },
  {
    "id": "e623d4ac.ab78a8",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "at m2x",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 822.1701126098633,
    "y": 248.61116409301758,
    "wires": [

    ]
  },
  {
    "id": "b5882a69.afe6f8",
    "type": "inject",
    "z": "828b2334.7d74e",
    "name": "Startup",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "",
    "crontab": "",
    "once": true,
    "x": 119.17361450195312,
    "y": 99.31597137451172,
    "wires": [
      [
        "8310d36c.89f88"
      ]
    ]
  },
  {
    "id": "8310d36c.89f88",
    "type": "function",
    "z": "828b2334.7d74e",
    "name": "Set Start",
    "func": "//global context is shared across all flows\n//persists until the project restarts or is redeployed\n\nglobal.set('start',msg.payload);\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 296.1839904785156,
    "y": 47.25346755981445,
    "wires": [
      [
        "136090b4.323d4f"
      ]
    ]
  },
  {
    "id": "1c110769.2f8279",
    "type": "comment",
    "z": "828b2334.7d74e",
    "name": "Initialize Flow",
    "info": "",
    "x": 106.17361450195312,
    "y": 40.142364501953125,
    "wires": [

    ]
  },
  {
    "id": "ad9071d1.a3e55",
    "type": "comment",
    "z": "828b2334.7d74e",
    "name": "Device Sensor Endpoints",
    "info": "",
    "x": 126.18403625488281,
    "y": 179.14238739013672,
    "wires": [

    ]
  },
  {
    "id": "bf109f89.fb686",
    "type": "inject",
    "z": "ff4604e.3bd1ef8",
    "name": "Sensor Reading",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "",
    "crontab": "",
    "once": false,
    "x": 124.18405151367188,
    "y": 101.97224426269531,
    "wires": [
      [
        "51647013.cc8ca"
      ]
    ]
  },
  {
    "id": "73b3da71.6cece4",
    "type": "http request",
    "z": "ff4604e.3bd1ef8",
    "name": "Climate",
    "method": "POST",
    "ret": "txt",
    "url": "",
    "configKey": "",
    "useAuth": false,
    "encryption": "none",
    "useCertificate": false,
    "decrypt": false,
    "cert": "",
    "key": "",
    "encryptObj": [
      "username",
      "password"
    ],
    "x": 521.1805725097656,
    "y": 103.70835876464844,
    "wires": [
      [
        "abf5b86c.7eaac8"
      ]
    ]
  },
  {
    "id": "abf5b86c.7eaac8",
    "type": "debug",
    "z": "ff4604e.3bd1ef8",
    "name": "http request",
    "active": false,
    "console": "false",
    "complete": "payload",
    "x": 728.1771545410156,
    "y": 107.388916015625,
    "wires": [

    ]
  },
  {
    "id": "cb554451.c15e18",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "http-in",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 201.1771240234375,
    "y": 292.39933013916016,
    "wires": [

    ]
  },
  {
    "id": "1d675a1d.cb9bb6",
    "type": "inject",
    "z": "ff4604e.3bd1ef8",
    "name": "Initialize",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "",
    "crontab": "",
    "once": false,
    "x": 121.54861450195312,
    "y": 612.8924140930176,
    "wires": [
      [
        "eee209ca.7f58e8"
      ]
    ]
  },
  {
    "id": "eee209ca.7f58e8",
    "type": "function",
    "z": "ff4604e.3bd1ef8",
    "name": "Data to Send",
    "func": "msg.payload = {\n    \"name\": global.get(\"name\"),\n    \"description\": global.get(\"description\"),\n    \"tags\": global.get(\"tags\"),\n    \"visibility\": global.get(\"visibility\"),\n    \"metadata\": {},\n    \"serial\": global.get(\"serial\")\n}\nmsg.url = global.get(\"Register\");\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 322.5382080078125,
    "y": 613.8472785949707,
    "wires": [
      [
        "46371adc.7b5074",
        "9b68d03e.b4628"
      ]
    ]
  },
  {
    "id": "9b68d03e.b4628",
    "type": "debug",
    "z": "ff4604e.3bd1ef8",
    "name": "data",
    "active": true,
    "console": "false",
    "complete": "true",
    "x": 524.5346984863281,
    "y": 668.3125877380371,
    "wires": [

    ]
  },
  {
    "id": "2012f90.f155608",
    "type": "debug",
    "z": "ff4604e.3bd1ef8",
    "name": "post request",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 708.5416564941406,
    "y": 614.3090476989746,
    "wires": [

    ]
  },
  {
    "id": "46371adc.7b5074",
    "type": "http request",
    "z": "ff4604e.3bd1ef8",
    "name": "",
    "method": "POST",
    "ret": "txt",
    "url": "",
    "configKey": "",
    "useAuth": false,
    "encryption": "none",
    "useCertificate": false,
    "decrypt": false,
    "cert": "",
    "key": "",
    "encryptObj": [
      "username",
      "password"
    ],
    "x": 518.5451354980469,
    "y": 614.6285285949707,
    "wires": [
      [
        "2012f90.f155608"
      ]
    ]
  },
  {
    "id": "30182977.730936",
    "type": "http in",
    "z": "dca3a3aa.29d59",
    "name": "Register",
    "url": "/register",
    "method": "post",
    "configKey": "",
    "authType": "noAuth",
    "useAuth": false,
    "useOauth": false,
    "encryption": "none",
    "realm": "",
    "site": "",
    "authorizationPath": "/oauth/authorize",
    "tokenPath": "/oauth/access_token",
    "scope": "",
    "encryptObj": [
      "username",
      "password",
      "clientId",
      "clientSecret"
    ],
    "swaggerDoc": "",
    "x": 124.66319274902344,
    "y": 91.8680648803711,
    "wires": [
      [
        "b21405df.00f8a8"
      ]
    ]
  },
  {
    "id": "95df9407.f4a3c8",
    "type": "debug",
    "z": "dca3a3aa.29d59",
    "name": "register",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 523.6666870117188,
    "y": 37.611106872558594,
    "wires": [

    ]
  },
  {
    "id": "e45aeb0f.6538b8",
    "type": "http response",
    "z": "dca3a3aa.29d59",
    "name": "",
    "x": 760.6597290039062,
    "y": 212.17365264892578,
    "wires": [

    ]
  },
  {
    "id": "136090b4.323d4f",
    "type": "metadata",
    "z": "828b2334.7d74e",
    "name": "",
    "x": 459.65625,
    "y": 46.03820037841797,
    "wires": [
      [
        "33bcd9d0.3b3346"
      ]
    ]
  },
  {
    "id": "efe4775b.6561e8",
    "type": "function",
    "z": "828b2334.7d74e",
    "name": "Configuration",
    "func": "// configure with your specific keys, username, and URL\n\nglobal.set('M2X-Key','8dd47dd3b7e35d1c5791a9fb52ba888c');\n\n// for the virtual starter kit or default values\n//global.set(\"deviceID\",'<get from M2X>');\nglobal.set(\"defaultserial\",'vstarterkit001');\nglobal.set(\"serial\",global.get(\"defaultserial\"));\nglobal.set(\"name\",\"Virtual Starter Kit\");\nglobal.set(\"description\",\"A virtual implementation of the Starter Kit for testing the data streams.\");\nglobal.set(\"tags\",\"starter-kit, virtual\");\nglobal.set(\"visibility\",\"private\");\n\n// reporting incorrect URLs\n/*for(var key in msg.payload) {\n    var item = msg.payload[key];\n    global.set(item.name,item.url);\n    data[item.name] = item.url;\n}*/\n// temp solution\nvar base_hostname = \"run-east.att.io\" // get from Endpoints after 1st Deploy\nvar base_uri = \"/1927af3b202de/87aee9e78e53/812734d6adb7168/in/flow\"\nvar base_url = \"https://\" + base_hostname + base_uri;\nglobal.set(\"Climate\",base_url+\"/climate\");\nglobal.set(\"ClimateUDP_IP\",base_hostname);\nglobal.set(\"ClimateUDP_Port\",34041); // get from Endpoints after 1st Deploy\nglobal.set(\"Register\",base_url+\"/register\");\nglobal.set(\"Trigger\",base_url+\"/trigger\");\nglobal.set(\"Command\",base_url+\"/command\");\nglobal.set(\"Poll\",base_url+\"/poll\");\n\n// Control Center credentials\nglobal.set(\"CCBaseURL\",\"https://rws-api.jasper.com/rws/api/v1/\");\nglobal.set(\"CCuser\",\"coolioxlr\");\nglobal.set(\"CCkey\",\"2947492c-b087-46cf-93fc-452307013c89\");\nglobal.set(\"ICCID\",\"89011704252314439420\");\n\nvar data = {\n    \"start\": global.get(\"start\"),\n    \"M2X-Key\": global.get(\"M2X-Key\")\n};\n\nmsg.payload = data;\nreturn msg;\n\n",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 613.6562347412109,
    "y": 102.14583587646484,
    "wires": [
      [
        "49c67e1.ecc9d8"
      ]
    ]
  },
  {
    "id": "49c67e1.ecc9d8",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "startup",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 801.3402709960938,
    "y": 102.8923568725586,
    "wires": [

    ]
  },
  {
    "id": "33bcd9d0.3b3346",
    "type": "json",
    "z": "828b2334.7d74e",
    "name": "",
    "x": 414.2396240234375,
    "y": 103.70487213134766,
    "wires": [
      [
        "efe4775b.6561e8"
      ]
    ]
  },
  {
    "id": "8441e01c.f2b98",
    "type": "inject",
    "z": "ff4604e.3bd1ef8",
    "name": "manual values - reset",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "",
    "crontab": "",
    "once": false,
    "x": 117.23612976074219,
    "y": 152.97919464111328,
    "wires": [
      [
        "8b1b39c6.5aa6f8"
      ]
    ]
  },
  {
    "id": "8b1b39c6.5aa6f8",
    "type": "function",
    "z": "ff4604e.3bd1ef8",
    "name": "reset",
    "func": "global.set(\"temp\",26); // celcius\nglobal.set(\"humidity\",83);\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 319.22918701171875,
    "y": 155.26392364501953,
    "wires": [
      [
        "51647013.cc8ca"
      ]
    ]
  },
  {
    "id": "a7cc948.65bc468",
    "type": "function",
    "z": "828b2334.7d74e",
    "name": "Calculate Heat Index - can you get it working?",
    "func": "msg.payload.tempF = msg.payload.temp * 1.8 + 32;\n\nvar HI;\nvar T = msg.payload.tempF;\nvar RH = msg.payload.humidity/100;\n\n// http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml\n\nHI = 0.5 * (T + 61.0 + ((T-68.0)*1.2) + (RH*0.094));\n\n/* if(HI >= 80) {\n    HI = -42.379 + 2.04901523*T + 10.14333127*RH - .22475541*T*RH - .00683783*T*T - .05481717*RH*RH + .00122874*T*T*RH + .00085282*T*RH*RH - .00000199*T*T*RH*RH;\n    if(RH < 13 && T >= 80 && T <= 112) {\n        HI -= ((13-RH)/4)*Math.sqrt((17-Math.abs(T-95))/17);\n    } else if(RH >= 85 && T >= 80 && T <= 87) {\n        HI += ((RH-85)/10) * ((87-T)/5)\n    }\n} */\n\nHI = Math.round(HI*100)/100;\n\nmsg.payload.indexF = HI;\nmsg.payload.index = (T - 32) / 1.8;\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 821.3402709960938,
    "y": 175.89237213134766,
    "wires": [
      [

      ]
    ]
  },
  {
    "id": "2c8bb750.f7b438",
    "type": "comment",
    "z": "ff4604e.3bd1ef8",
    "name": "Register this Device - only use once",
    "info": "",
    "x": 174.23959350585938,
    "y": 560.8056259155273,
    "wires": [

    ]
  },
  {
    "id": "a6fe7774.136c38",
    "type": "debug",
    "z": "dca3a3aa.29d59",
    "name": "extract info",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 763.2361450195312,
    "y": 153.08683013916016,
    "wires": [

    ]
  },
  {
    "id": "ff94ed1a.b9a14",
    "type": "function",
    "z": "dca3a3aa.29d59",
    "name": "Extract Device info",
    "func": "var deviceID = msg.payload.id;\nvar serial = msg.payload.serial;\nvar key = msg.payload.key;\n\nglobal.set(\"deviceID\",deviceID);\nglobal.set(\"serial\", serial);\nglobal.set(\"deviceKey\",key);\n\n// typically, this would be stored in a data store somewhere else\nglobal.set(\"dict:serial:\"+deviceID, serial);\nglobal.set(\"dict:id:\"+serial, deviceID);\n\nmsg.payload = {\n    \"deviceID\": deviceID,\n    \"serial\": serial,\n    \"deviceKey\": key\n}\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 521.232666015625,
    "y": 230.1424217224121,
    "wires": [
      [
        "a6fe7774.136c38",
        "51115a1.db7a6a4",
        "e45aeb0f.6538b8"
      ]
    ]
  },
  {
    "id": "db884774.bea118",
    "type": "debug",
    "z": "dca3a3aa.29d59",
    "name": "m2x response",
    "active": false,
    "console": "false",
    "complete": "payload",
    "x": 838.3401336669922,
    "y": 410.8923110961914,
    "wires": [

    ]
  },
  {
    "id": "51115a1.db7a6a4",
    "type": "function",
    "z": "dca3a3aa.29d59",
    "name": "M2X lead-in",
    "func": "msg.headers = {\n    \"X-M2X-KEY\": global.get(\"M2X-Key\"),\n    \"content-type\": \"application/json\"\n};\n//msg.topic = \"devices\";\n//msg.action = \"updateStream\";\n//msg.topic_id = msg.payload.deviceID;\nmsg.url = \"https://api-m2x.att.com/v2/devices/\" + msg.payload.deviceID + \"/\";\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 164.34027099609375,
    "y": 321.89237213134766,
    "wires": [
      [
        "8ee96b4b.18b448",
        "e7ed3778.b64da8",
        "8486001d.43141",
        "b13fcd55.36559"
      ]
    ]
  },
  {
    "id": "8ee96b4b.18b448",
    "type": "function",
    "z": "dca3a3aa.29d59",
    "name": "Set up Temp Stream",
    "func": "msg.url += \"streams/temp\";\n\nmsg.payload = {\n    \"display_name\": \"Temperature\",\n    \"unit\": {\n        \"label\": \"degree Celsius\",\n        \"symbol\": \"°C\"\n    },\n    \"type\": \"numeric\"\n};\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 384.34027099609375,
    "y": 415.89231872558594,
    "wires": [
      [
        "bed41f26.76a9c"
      ]
    ]
  },
  {
    "id": "e7ed3778.b64da8",
    "type": "function",
    "z": "dca3a3aa.29d59",
    "name": "Set up Humidity Stream",
    "func": "msg.url += \"streams/humidity\";\n\nmsg.payload = {\n    \"display_name\": \"Humidity\",\n    \"unit\": {\n        \"label\": \"percentage\",\n        \"symbol\": \"%\"\n    },\n    \"type\": \"numeric\"\n};\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 387.34027099609375,
    "y": 370.8923645019531,
    "wires": [
      [
        "bed41f26.76a9c"
      ]
    ]
  },
  {
    "id": "8486001d.43141",
    "type": "function",
    "z": "dca3a3aa.29d59",
    "name": "Set up Heat Index Stream",
    "func": "//msg.sub_topic_id = \"heatIndex\";\nmsg.url += \"streams/heatIndex\";\nmsg.payload = {\n    \"display_name\": \"Heat Index\",\n    \"unit\": {\n        \"label\": \"degree Celsius\",\n        \"symbol\": \"°C\"\n    },\n    \"type\": \"numeric\"\n};\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 397.34027099609375,
    "y": 322.89234924316406,
    "wires": [
      [
        "bed41f26.76a9c"
      ]
    ]
  },
  {
    "id": "2e2ddedb.c570e2",
    "type": "comment",
    "z": "dca3a3aa.29d59",
    "name": "Web Service for Device Registration",
    "info": "Only needed one time over all.  Calling this\nservice will create a device in M2X along with\nthe necessary streams.  After its called once,\nset the values in the Configuration function\nnode.\n\nFor this to work you'll need to configure the\ntwo M2X nodes to use your M2X configuration,\nwhich consists of simply the M2X master key.",
    "x": 178.24305725097656,
    "y": 43.482635498046875,
    "wires": [

    ]
  },
  {
    "id": "959fdbe5.9f9538",
    "type": "comment",
    "z": "dca3a3aa.29d59",
    "name": "Extra New Device Info and Save to Context Variables",
    "info": "This will populate the global context scope\nwith deviceID and deviceKey for this device.\n\nWatch the Debug panel for these values. They\ncan also be found in M2X itself.",
    "x": 212.24305725097656,
    "y": 178.1388816833496,
    "wires": [

    ]
  },
  {
    "id": "6d36a811.816578",
    "type": "comment",
    "z": "dca3a3aa.29d59",
    "name": "Set up New Streams",
    "info": "",
    "x": 135.23611450195312,
    "y": 279.25,
    "wires": [

    ]
  },
  {
    "id": "4da56a78.d88c04",
    "type": "function",
    "z": "828b2334.7d74e",
    "name": "M2X lead-in",
    "func": "//Post multiple values to multiple streams example\n\nvar timestamp = msg.payload.timestamp || new Date().getTime();\ntimestamp = new Date(timestamp).toISOString();\n\n//msg.topic = \"devices\";\n//msg.action = \"postMultiple\";\n//msg.topic_id = msg.payload.deviceID || global.get(\"deviceID\");\nmsg.url = \"https://api-m2x.att.com/v2/devices/\";\nif(msg.payload.deviceID) {\n    var deviceID = msg.payload.deviceID || global.get(\"deviceID\");\n    msg.url += deviceID + \"/updates\";\n} else if(msg.payload.serial) {\n    msg.url += \"serial/\" + msg.payload.serial + \"/updates\";\n}\n\nmsg.headers = {\n    \"X-M2X-KEY\": global.get(\"M2X-Key\"),\n    \"content-type\": \"application/json\"\n};\n\nmsg.payload = {\n    \"values\": {\n    \"temp\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.temp  }],\n    \"humidity\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.humidity  }],\n    \"heatIndex\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.heatIndex  }],\n    \"accelX\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.accelX  }],\n    \"accelY\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.accelY  }],\n    \"accelZ\": [\n        { \"timestamp\": timestamp, \"value\": msg.payload.accelZ  }]\n    }\n};\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "dependencies": [

    ],
    "x": 719.2431335449219,
    "y": 304.42362213134766,
    "wires": [
      [
        "e623d4ac.ab78a8",
        "d28b3f50.a99a8",
        "25497871.c15828"
      ]
    ]
  },
  {
    "id": "4ddb6902.4d65e8",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "heat index",
    "active": false,
    "console": "false",
    "complete": "payload",
    "x": 712.3402099609375,
    "y": 447.2257080078125,
    "wires": [

    ]
  },
  {
    "id": "4cb8e2ed.d6c6cc",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "m2x response",
    "active": true,
    "console": "false",
    "complete": "payload",
    "x": 1029.2291564941406,
    "y": 250.55902862548828,
    "wires": [

    ]
  },
  {
    "id": "6a05023c.0e670c",
    "type": "comment",
    "z": "ff4604e.3bd1ef8",
    "name": "Send Sensor Data over HTTPS",
    "info": "You will need to copy the endpoint from the\nClimate HTTP-IN node in the Data flow (see the\nEndpoints tab below) and use it to configure\nthe Climate HTTP-REQUEST node here.",
    "x": 141.3194580078125,
    "y": 47.08680725097656,
    "wires": [

    ]
  },
  {
    "id": "47889ebf.219bc",
    "type": "inject",
    "z": "ff4604e.3bd1ef8",
    "name": "Sensor Reading",
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "repeat": "",
    "crontab": "",
    "once": false,
    "x": 113.51040649414062,
    "y": 303.89237213134766,
    "wires": [
      [
        "f4746521.9c739"
      ]
    ]
  },
  {
    "id": "cb0a19f7.8e8338",
    "type": "udp out",
    "z": "ff4604e.3bd1ef8",
    "name": "Climate",
    "addr": "",
    "iface": "",
    "port": "",
    "ipv": "udp4",
    "outport": "",
    "base64": false,
    "multicast": "false",
    "x": 798.09716796875,
    "y": 301.28131103515625,
    "wires": [

    ]
  },
  {
    "id": "d707667a.627b78",
    "type": "debug",
    "z": "828b2334.7d74e",
    "name": "udp-in",
    "active": false,
    "console": "false",
    "complete": "payload",
    "x": 434.51039123535156,
    "y": 442.89233137648785,
    "wires": [

    ]
  },
  {
    "id": "c69b666b.6ee328",
    "type": "base64",
    "z": "828b2334.7d74e",
    "name": "decode",
    "method": "decode",
    "x": 315.10069274902344,
    "y": 442.8714904785156,
    "wires": [
      [
        "d707667a.627b78",
        "96644c3d.0334"
      ]
    ]
  },
  {
    "id": "65a39d98.998ae4",
    "type": "json",
    "z": "ff4604e.3bd1ef8",
    "name": "",
    "x": 637.0867919921875,
    "y": 300.09381103515625,
    "wires": [
...

This file has been truncated, please download it to see its full contents.

Smart City Air Monitor open source code

The code includes use of AT&T Starter kit transferring data to M2X, the Air Quality monitor code through Edison using XDK, and M2X triggering Android app.

Smart City Air Monitor Site

The website used to host Smart City Air Monitor

Credits

Peter Ma

Peter Ma

49 projects • 394 followers
Prototype Hacker, Hackathon Goer, World Traveler, Ecological balancer, integrationist, technologist, futurist.
Mica Wong

Mica Wong

3 projects • 10 followers
Self taught 3D modeling and printing skills. Work at a grooming salon part time and delve into projects and hackathons as hobby.
Ethan Fan

Ethan Fan

9 projects • 35 followers
Mobile, Watch, and Glass Developer

Comments