{"id":29014053,"url":"https://github.com/armmbed/sxsw2018","last_synced_at":"2025-07-13T14:34:43.737Z","repository":{"id":72728372,"uuid":"123963297","full_name":"ARMmbed/sxsw2018","owner":"ARMmbed","description":"Workshop materials for Arm / TTN session during SXSW 2018: \"Changing the World with Open, Long-Range IoT\"","archived":false,"fork":false,"pushed_at":"2018-03-14T19:22:02.000Z","size":5961,"stargazers_count":5,"open_issues_count":1,"forks_count":3,"subscribers_count":98,"default_branch":"master","last_synced_at":"2025-06-25T20:12:42.390Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ARMmbed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-03-05T18:48:24.000Z","updated_at":"2021-08-12T20:38:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"2be5c1cc-7d12-43d3-ad9f-916313200250","html_url":"https://github.com/ARMmbed/sxsw2018","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ARMmbed/sxsw2018","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARMmbed%2Fsxsw2018","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARMmbed%2Fsxsw2018/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARMmbed%2Fsxsw2018/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARMmbed%2Fsxsw2018/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ARMmbed","download_url":"https://codeload.github.com/ARMmbed/sxsw2018/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ARMmbed%2Fsxsw2018/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265156196,"owners_count":23719675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-25T20:12:41.452Z","updated_at":"2025-07-13T14:34:43.726Z","avatar_url":"https://github.com/ARMmbed.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SXSW 2018 - Changing the World with Open, Long-Range IoT\n\nWelcome to our session at SXSW 2018. If you have any questions, please just give a shout. We are here to help.\n\nIn this session you'll be building five examples, introducing you to:\n\n1. Building IoT devices with [Arm Mbed OS](https://os.mbed.com/).\n1. Hooking up an optical particle sensor to a development board.\n1. Connecting your device to [The Things Network](https://www.thethingsnetwork.org/) using LoRaWAN.\n1. Data visualization of particle sensors.\n1. Drawing all sensors on a single map, giving live insight in Austin's pollution numbers.\n\nIn case you're stuck this document will help you get back on track. If you're a fast learner, there are 'extra credit'-assignments at the end of each section. Please help your neighbours as well :-)\n\n## Prerequisites\n\n1. Create an Arm Mbed online account [here](https://os.mbed.com/account/signup/).\n1. Then install the following software for your operating system below.\n\n**Windows**\n\nIf you are on Windows, install:\n\n1. [Arm Mbed Windows serial driver](http://os.mbed.com/media/downloads/drivers/mbedWinSerial_16466.exe) - serial driver for the board.\n\n    **Note:** Not needed on Windows 10.\n\n1. [Tera term](https://osdn.net/projects/ttssh2/downloads/66361/teraterm-4.92.exe/) - to see debug messages from the board.\n1. [Node.js](https://nodejs.org/en/download/) - to show visualizations.\n\n**Linux**\n\nIf you're on Linux, install:\n\n1. screen - e.g. via `sudo apt install screen`\n1. [Node.js](https://nodejs.org/en/download/) - to show visualizations.\n\n**MacOS**\n\nIf you're on MacOS, install:\n\n1. [Node.js](https://nodejs.org/en/download/) - to show visualizations.\n\n## Building the circuit\n\nWe're using the [L-TEK FF1705](https://os.mbed.com/platforms/L-TEK-FF1705/) development board, which contains the Multi-Tech xDot module. In addition you'll have a battery holder, some batteries and an optical particle sensor. Let's connect these sensors and verify that the board works.\n\nGrab the following items:\n\n* Development board.\n* Micro-USB cable.\n* Optical particle sensor.\n* 3x jumper wires.\n* A box.\n* Battery pack + batteries.\n\nThe particle sensor needs to be in the box, because it needs to have consistent lighting. Place the sensor in the box like this (use some velcro):\n\n![Dust sensor in a box](media/dust1.jpg)\n\nTo connect the particle sensor you use the yellow, red and black wires. We'll use the jumper wires to connect the sensor to the board (because we don't have Grove base shields).\n\nPlug the jumper wires into the Grove connector, and connect:\n\n* Red -\u003e 5V\n* Black -\u003e GND\n* Yellow -\u003e GPIO3\n\n![Wires](media/dust2.jpg) ![Wires](media/dust3.jpg)\n\n## 1. A simple application\n\nNow let's build a simple application which reads the sensor data and prints it to the serial console. Note that it takes three minutes to get the sensor to warm up!\n\n1. Go to [https://os.mbed.com](https://os.mbed.com) and sign up (or sign in).\n1. Go to the [L-TEK FF1705](https://os.mbed.com/platforms/L-TEK-FF1705/) platform page and click *Add to your Mbed compiler*.\n\n    ![Add to your Mbed compiler](media/mbed1.png)\n\n1. Import the example program into the Arm Mbed Compiler by clicking [this link](https://os.mbed.com/compiler/#import:https://github.com/armmbed/sxsw2018).\n1. Click *Import*.\n\n    ![Importing the SXSW2018 repo](media/mbed6.png)\n\n1. In the top right corner make sure you selected 'L-TEK FF1705'.\n\n    ![Select right platform](media/mbed3.png)\n\nThis has cloned the repository. There are a few examples here, so let's switch between them.\n\n1. Open `firmware/select_project.h`.\n1. Change the project to `1`.\n\n    ![Changing project](media/mbed10.png)\n\n1. To see the code, see `1_blinky/main.cpp`, it's pretty straight forward!\n1. Click *Compile*.\n\n    ![Compile](media/mbed4.png)\n\n1. 1. A binary (.bin) file downloads, use drag-and-drop to drag the file to the DAPLINK device (like a USB mass storage device).\n\n    **Note:** Here's a [video](https://youtu.be/L5TcmFFD0iw?t=1m25s).\n\n1. When flashing is complete, hit the **RESET** button on the board (next to USB).\n\nYou should see the blue LED blink very fast. Your first program is running! Let's look at the logs now.\n\n### Extra credit\n\nThe LED blinks automatically. But you can also make it user controlled through the push button on the board. To handle events coming from a physical device you can use interrupts. These fire off when the state of a physical switch changes. You can handle them as follows:\n\n```cpp\nvoid fall_handler() {\n    // button is pressed\n}\n\nvoid rise_handler() {\n    // button is no longer pressed\n}\n\nInterruptIn btn(BUTTON1);\n\nint main() {\n    btn.fall(\u0026fall_handler);\n    btn.rise(\u0026rise_handler);\n}\n```\n\nChange the code so that the LED responds to the button instead of through a timer.\n\n## 2. Showing logs\n\nIf all is well, you should see something similar to:\n\n```\nBlink! LED is now 1\nBlink! LED is now 0\nBlink! LED is now 1\nBlink! LED is now 0\nBlink! LED is now 1\n```\n\n#### Windows\n\nTo see debug messages, install:\n\n1. [Arm Mbed Windows serial driver](http://os.mbed.com/media/downloads/drivers/mbedWinSerial_16466.exe) - serial driver for the board.\n    * See above for more instructions.\n    * No need to install this if you're on Windows 10.\n1. [Tera term](https://osdn.net/projects/ttssh2/downloads/66361/teraterm-4.92.exe/) - to see debug messages from the board.\n\nWhen you open Tera Term, select *Serial*, and then select the Mbed COM port.\n\n![Tera Term](media/mbed5.png)\n\n#### OS/X\n\nNo need to install a driver. Open a terminal and run:\n\n```\nscreen /dev/tty.usbm            # now press TAB to autocomplete and then ENTER\n```\n\nTo exit, press: `CTRL+A` then `CTRL+\\` then press `y`.\n\n#### Linux\n\nIf it's not installed, install GNU screen (`sudo apt-get install screen`). Then open a terminal and find out the handler for your device:\n\n```\n$ ls /dev/ttyACM*\n/dev/ttyACM0\n```\n\nThen connect to the board using screen:\n\n```\nsudo screen /dev/ttyACM0 9600                # might not need sudo if set up lsusb rules properly\n```\n\nTo exit, press `CTRL+A` then type `:quit`.\n\n## 3. Getting data from the dust sensor\n\nNow let's grab some data from the dust sensor. Make sure you've connected it properly to your device, and that it's in an upright position (I feel like I'm an airline steward) in the box.\n\n1. Go into `select_project.h` and change the project to `2`.\n1. Inspect the code in `2_dust_sensor/main.cpp`.\n1. Click *Compile*.\n1. A file downloads, use drag-and-drop to drag the file to the DAPLINK device (like a USB mass storage device).\n\nInspect the logs on the device, and see the sensor counting dust particles. Blow into the sensor or spray something around the air to change it around. A measurement takes 30 seconds.\n\nYour log messages should look like:\n\n```\nStart measuring...\nlpo = 589396, r = 1.964653, c = 1015.913879 pcs/0.01cf\nStart measuring...\nlpo = 401956, r = 1.339853, c = 693.167725 pcs/0.01cf\n```\n\nThe `c` value is the concentration of particles.\n\n### Extra credit\n\nDust particles is just one of the things we can measure. How about temperature and humidity? We have some extra sensors with us that can do this. Grab one and see if you can change the program so that it measures both dust + temperature + humidity. The component page - which contains drivers and example code - for the sensor is [here](https://os.mbed.com/components/Grove-TempHumi-Sensor/).\n\n### Extra credit (2)\n\nWe're blocking the main thread right now while we're waiting for the dust measurement to come in. That gets complicated very quickly when dealing with multiple sensors. To deal with this Mbed contains an RTOS - a real-time operating system - where you can spawn threads. That's very useful in these contexts. To spin up a new thread do this:\n\n```cpp\nvoid new_thread_main() {\n    // run your code here\n}\n\nThread new_thread;\n\nint main() {\n    new_thread.start(\u0026new_thread_main);\n}\n```\n\nChange the code so it runs the temperature and humidity measurements in a different thread.\n\n## 4. Connecting to The Things Network\n\nNow it's time to send this data to the internet over LoRaWAN.\n\n1. Open `select_project.h` and change the project to 3.\n\nWe need to program some keys in the device. LoRaWAN uses an end-to-end encryption scheme that uses two session keys. The network server holds one key, and the application server holds the other. (In this tutorial, TTN fulfils both roles). These session keys are created when the device joins the network. For the initial authentication with the network, the application needs its device EUI, the EUI of the application it wants to join (referred to as the application EUI) and a preshared key (the application key).\n\nLet's register this device in The Things Network and grab some keys!\n\n### Connecting to The Things Network\n\n#### Setting up\n\n1. Go to [The Things Network Console](https://console.thethingsnetwork.org)\n2. Login with your account or click [Create an account](https://account.thethingsnetwork.org/register)\n\n   ![console](media/console.png)\n\n   \u003eThe Console allows you to manage Applications and Gateways.\n\n3. Click **Applications**\n4. Click **Add application**\n5. Enter a **Application ID** and **Description**, this can be anything\n6. Be sure to select `ttn-handler-us-west` in **Handler registration**\n\n   ![add-application](media/add-application.png)\n\n   \u003eThe Things Network is a global and distributed network. Selecting the Handler that is closest to you and your gateways allows for higher response times.\n\n7. Click **Add application**\n\n   ![application-overview](media/application-overview.png)\n\n   \u003eLoRaWAN devices send binary data to minimize the payload size. This reduces channel utilization and power consumption. Applications, however, like to work with JSON objects or even XML. In order to decode binary payload to an object, The Things Network supports [CayenneLPP](https://www.thethingsnetwork.org/docs/devices/arduino/api/cayennelpp.html) and Payload Functions: JavaScript lambda functions to encode and decode binary payload and JSON objects. In this example, we use CayenneLPP.\n\n8. Go to **Payload Format** and select **CayenneLPP**\n\n   ![payload-format](media/payload-format.png)\n\n#### Registering your Device\n\n1. In your application, go to **Devices**\n2. Click **register device**\n3. Enter a **Device ID**\n4. Look very closely at the Multi-Tech xDot on your L-Tek FF1705, the **Device EUI** is printed after **NODE**:\n\n   ![node-eui](media/node-eui.jpg)\n\n   \u003eThe EUI starts with `00:80:00:00:...`. Enter without the colons.\n\n   ![register-device](media/register-device.png)\n\n   \u003eYou can leave the Application EUI to be generated automatically.\n\n5. Click **Register**\n\n   ![device-overview](media/device-overview.png)\n\n   \u003eYour device needs to be programmed with the **Application EUI** and **App Key**\n\n7. Click the `\u003c \u003e` button of the **Application EUI** and **App Key** values to show the value as C-style array\n8. Click the **Copy** button on the right of the value to copy to clipboard\n\n   ![copy-appeui](media/copy-appeui.png)\n\n\n#### Pasting them in the Online Compiler\n\nIn the Online Compiler now open `firmware/src/ttn_config.h`, and paste the Application EUI and Application Key in:\n\n![Put in the keys](media/mbed7.png)\n\n**Note:** Do not forget the `;` after pasting.\n\nNow click *Compile* and flash the application to your board again. The board should now connect to The Things Network. Inspect the *Data* tab in the TTN console to see the device connecting. You should first see a 'join request', then a 'join accept', and then data flowing in.\n\n![console-data](media/console-data.png)\n\n**Note:** Device not joining? Maybe your EUI is wrong, they're hard to read. On the serial console the EUI is printed. Check if it's the same as in the TTN console. Wrong? Click *Edit* in the TTN console and update the EUI.\n\n### Extra credit - relaying data back to the device\n\nWe only *send* messages to the network. But you can also relay data back to the device. Note that LoRaWAN devices can only receive messages when a RX window is open. This RX window opens right after a transmission, so you can only relay data back to the device right after sending.\n\nTo send some data to the device:\n\n1. Open the device page in the TTN console.\n1. Under 'Downlink', enter some data under 'Payload' and click *Send*.\n1. Inspect the logs on the device to see the device receive the message - note that messages are not guaranteed to end up at the device. The 'Confirmed' flag can help if this is a necessity.\n\nNow let's do something useful... Control the LED on the board over LoRaWAN.\n\nLook at `RadioEvent.h` to the line where the messages are received. Now change the behavior so that the LED toggles on/off quickly after a message is received.\n\n*Disabling LED sleep behavior*\n\nThe LED still turns off when the device goes into sleep. This is a power-saving measurement. To disable sleep behavior for the LED:\n\n1. In `dot_util.cpp` change:\n\n    ```cpp\n        if (dot-\u003egetWakePin() != GPIO0 || dot-\u003egetWakeMode() == mDot::RTC_ALARM) {\n            GPIO_InitStruct.Pin = GPIO_PIN_4;\n            GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;\n            GPIO_InitStruct.Pull = GPIO_NOPULL;\n            HAL_GPIO_Init(GPIOA, \u0026GPIO_InitStruct);\n        }\n    ```\n\n    into:\n\n    ```cpp\n        if (dot-\u003egetWakePin() != GPIO0 || dot-\u003egetWakeMode() == mDot::RTC_ALARM) {\n            // GPIO_InitStruct.Pin = GPIO_PIN_4;\n            // GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;\n            // GPIO_InitStruct.Pull = GPIO_NOPULL;\n            // HAL_GPIO_Init(GPIOA, \u0026GPIO_InitStruct);\n        }\n    ```\n\n1. In `dot_util.cpp` change:\n\n    ```cpp\n    // PB_0, PB_1, PB_3 \u0026 PB_4 to analog nopull\n    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4;\n    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;\n    GPIO_InitStruct.Pull = GPIO_NOPULL;\n    HAL_GPIO_Init(GPIOB, \u0026GPIO_InitStruct);\n    ```\n\n    into:\n\n    ```cpp\n    // PB_0, PB_1, PB_3 \u0026 PB_4 to analog nopull\n    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3; // | GPIO_PIN_4;\n    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;\n    GPIO_InitStruct.Pull = GPIO_NOPULL;\n    HAL_GPIO_Init(GPIOB, \u0026GPIO_InitStruct);\n    ```\n\n1. Those changes will no longer shut down the LED when the device is asleep.\n\n### Extra credit (2) - Sending temperature and humidity data\n\nParticle count is just one thing. Change the code so that it also sends temperature and humidity data off another sensor. More information can be found in the extra credit section in 3.\n\nCayenneLPP format already knows about temperature and humidity, so you can do:\n\n```cpp\npayload.addTemperature(2, 23.21f); // on channel 2, send temperature 23.21 degrees celcius\npayload.addRelativeHumidity(3, 48.12f); // on channel 3, send 48.12 humidity\n```\n\n## 5. Getting data out of The Things Network\n\nTo get some data out of The Things Network you can use their API. Today we'll use the node.js API, but there are many more.\n\nFirst, you need the application ID, and the application key.\n\n1. Open the TTN console and go to your application.\n1. Your application ID is noted on the top, write it down.\n\n    ![TTN App ID](media/ttn17.png)\n\n1. Your application Key is at the bottom of the page. Click the 'show' icon to make it visible and note it down.\n\n    ![TTN App Key](media/ttn18.png)\n\nWith these keys we can write a Node.js application that can retrieve data from TTN.\n\n1. Open a terminal or command prompt.\n1. Create a new folder:\n\n    ```\n    $ mkdir sxsw-ttn-api\n    $ cd sxsw-ttn-api\n    ```\n\n1. In this folder run:\n\n    ```\n    $ npm install ttn blessed blessed-contrib\n    ```\n\n1. Create a new file `server.js` in this folder, and add the following content (replace YOUR_APP_ID and YOUR_ACCESS_KEY with the respective values from the TTN console):\n\n    ```js\n    let TTN_APP_ID = 'YOUR_APP_ID';\n    let TTN_ACCESS_KEY = 'YOUR_ACCESS_KEY';\n\n    const ttn = require('ttn');\n\n    TTN_APP_ID = process.env['TTN_APP_ID'] || TTN_APP_ID;\n    TTN_ACCESS_KEY = process.env['TTN_ACCESS_KEY'] || TTN_ACCESS_KEY;\n\n    ttn.data(TTN_APP_ID, TTN_ACCESS_KEY).then(client =\u003e {\n        client.on('uplink', (devId, payload) =\u003e {\n            console.log('retrieved uplink message', devId, payload);\n        });\n\n        console.log('Connected to The Things Network data channel');\n    });\n    ```\n\n1. Now run:\n\n    ```\n    $ node server.js\n    ```\n\nThe application authenticates with the The Things Network and receives any message from your device.\n\n**Showing simple graphs**\n\nWe can also graph the values directly to the console. Replace `server.js` with:\n\n```js\nlet TTN_APP_ID = 'YOUR_APP_ID';\nlet TTN_ACCESS_KEY = 'YOUR_ACCESS_KEY';\n\nconst ttn = require('ttn');\nconst blessed = require('blessed');\nconst contrib = require('blessed-contrib');\nconst screen = blessed.screen();\nconst line = contrib.line({ width: 80, height: 20, left: 0, bottom: 0, xPadding: 5, yPadding: 10, minY: 0, maxY: 5, numYLabels: 7 });\n\nlet data = [\n    { title: 'Air pollution',\n        x: [ ],\n        y: [ ],\n        style: {\n            line: 'red'\n        }\n    }\n];\n\nTTN_APP_ID = process.env['TTN_APP_ID'] || TTN_APP_ID;\nTTN_ACCESS_KEY = process.env['TTN_ACCESS_KEY'] || TTN_ACCESS_KEY;\n\nlet series = [];\n\nttn.data(TTN_APP_ID, TTN_ACCESS_KEY).then(client =\u003e {\n    client.on('uplink', (devId, payload) =\u003e {\n        // console.log('retrieved uplink message', devId, payload.payload_fields.analog_in_1 * 100);\n\n        data[0].x.push(new Date(payload.metadata.time).toLocaleTimeString().split(' ')[0]);\n        data[0].y.push(payload.payload_fields.analog_in_1 * 100);\n\n        line.setData(data);\n        screen.render();\n    });\n\n    console.log('Connected to The Things Network data channel');\n});\n\n\nscreen.append(line); //must append before setting data\n\nscreen.key(['escape', 'q', 'C-c'], function(ch, key) {\n  return process.exit(0);\n});\n```\n\n### Extra credit\n\nThere's some limitations in our current graph:\n\n1. It only shows a single device at the same time.\n1. The graph is drawn in the console.\n\nSome extra credit excercises:\n\n1. Change the application so that it can show multiple devices at the same time.\n    * You can achieve this by inspecting `payload.dev_id` - this is the device that the message originated from.\n    * Add a new series for every device that you see.\n    * Work with your neighbor to get multiple devices in your application (they need to change their keys to your app).\n1. Turn this demo into a web application.\n    * Node.js + socket.io can be used to push new events down to the browser ([tutorial here](http://www.programwitherik.com/getting-started-with-socket-io-node-js-and-express/)).\n    * Send the events from TTN -\u003e your node app -\u003e browser, and graph them in the browser.\n1. Storing data.\n    * At the moment nothing is stored.\n    * Store the data in a file, or in a database and read that back when you start the application.\n\n## 6. A web application to show all your devices\n\nLet's visualize your data in a proper way. We have built a web application that will show all sensors on a map and then graphs the dust count. It works both in your browser and on your phone :-)\n\n![Web app](media/mbed11.png)\n\nThere's two ways you can run this web app, locally, just showing your own data; or you can use the hosted version, where we can show data from all sensors. Let's run it locally first, so you can change things.\n\n1. [Download the repository for this workshop](https://github.com/ARMmbed/sxsw2018/archive/master.zip).\n1. Unzip the package.\n1. Open a terminal or command prompt and navigate to the folder where you unzip'ed the package.\n1. Run:\n\n    ```\n    $ cd webapp\n    $ npm install\n    ```\n\n1. Open `server.js` in the webapp folder.\n1. From the terminal, run:\n\n    ```\n    $ node server.js\n    ```\n\n1. Open your web browser and navigate to http://localhost:5270.\n1. On the web page, enter your application ID in the text box and click *Connect*. Then enter your access key to connect.\n\nSensors should automatically show up now! You can also show sensors from other people, you just need their app ID and access key. Ask your neighbors!\n\nMarkers can be dragged around to mark where they are deployed. This is done in sync, open two web browsers, and see markers moving on both sides!\n\n**Extra credit (1) - Marker colors**\n\nThe markers are always red. Change the color of the marker depending on current dust levels. You can change the marker icon via:\n\n```js\nmarker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')\n```\n\n**Extra credit (2) - Temperature / humidity data**\n\nRemember the temperature and humidity sensors from 3. and 4.? Add that information to the map as well. Look in `maps.js` to see how we do the graphing (it's pretty simple). Data is being sent over a websocket to the browser (see `server.js`). Handle the events and update the graph accordingly.\n\n## 7. Let's build this thing together\n\nWe want this data set to be practical, and outlive SXSW! For this purpose we have hosted the web application on a public server. It'd be great if you can all add your device to the map.\n\n1. Go to the TTN console and add a new access key.\n1. Go to [the hosted application](http://sxsw2018.thethings.network).\n1. On the web page, enter your application ID in the text box and click *Connect*. Then enter your new access key to connect.\n1. See the glorious map showing all devices!\n\n![Victory](media/victory.gif)\n\nDone already? Go do some extra credit work!\n\n**Add coverage**\n\nThe Things Network is a collaborative network. You can extend the network yourself by placing a gateway, or you can use existing coverage from community members. See [The Things Network Map](https://www.thethingsnetwork.org/map) to see if there is coverage in your area or region.\n\nSetting up a gateway is easy and becomes more and more affordable. Here are two recommended options:\n\n1. The highly configurable [MultiTech Conduit](https://www.digikey.com/en/product-highlight/m/multi-tech-systems/iot-platform); you need an `MTAC-LORA-915` or `MTAC-LORA-868` depending [on your country](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html), as well as a `MTCDT` Conduit;\n1. The Things Network's own product, [The Things Gateway 915 MHz](http://www.newark.com/productimages/standard/en_US/05AC1807-40.jpg) or [The Things Gateway 868 MHz](http://uk.farnell.com/the-things-network/ttn-gw-868/the-things-gateway-eu/dp/2675813)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farmmbed%2Fsxsw2018","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farmmbed%2Fsxsw2018","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farmmbed%2Fsxsw2018/lists"}