###### tags: `TA Stuff 2021` `Pycom` `ESP32`
# TTS-Ubidots
In the previous [TTS tutorial](https://hackmd.io/@lnu-iot/rkWOVue6_), we left things off at sending payload/data. In this tutorial, you will learn how to visualize the data you send to TTS.
### Table of Contents
[TOC]
## Create a Ubidots STEM Account
First, you need to create your Ubidots stem account [here](https://ubidots.com/stem/). Once you're registered, you will be redirected to the following page:

## Create a Ubidots Data Plugin
Navigate to `Devices` and select `plugins`.
:::warning
Ubidots STEM accounts can only have one data plugin, so if you already have one configured for e.g. Helium, then remove it and create a new one.
:::
To create a new Data Plugin, select the `Create Data Plugin` button and choose `The Things Stack`.

:::info
There are two plugins available for TTS. The one we use in this tutorial is the one for receiving and decoding data from LoRaWAN devices.
:::
Confirm your choice by pressing the turquoise right-arrow and select the `Default token` as your `Ubidots Token` from the drop-down menu.

Now, finish the configuration by giving your plugin a name and description (in the next step). This is what you should see.

Give your plugin a few seconds to fire up and refresh the page. Now, you should see the pluging running.
## Create a TTS webhook
Now that you have created a Ubidots Data Plugin, revisit your TTS application and navigate to `Integrations/Webhooks`. Select the `Add webhook` button located in the top-right corner and choose `Ubidots`.
Give your webhook an appropriate name (can be anything).
Then, navigate to `Devices->Plugins` in Ubidots and select your TTS plugin. Once there, you can find your `Plugin ID` in the page URL.

The `Plugin ID` in the example image above is `60ef11c04763e72fe7e16090`. Add this as `Plugin ID` in TTS.
Finally, enter your `Ubidots token` in TTS, which can be found in `My Profile->API Credentials` or [here](https://stem.ubidots.com/accounts/me/apiCredentials).

Now, create the webhook. It should now be listed under `Integrations->Webhooks` in your TTS console. Select it, and scroll down to `Enabled messages`.

Replace the default `Uplink message` url with the one provided for you in the Ubidots Data Plugin you created earlier. You can find it by nagivating to `Devices->Plugins->YourPlugin->Decoder` and copying `HTTPs Endpoint URL` of the plugin. You dont need the whole URL, only the part from `/api`, so your `Uplink message` url should look something like:
`/api/web-hook/kxSCgvP93BUJXL25gUQCErvvJrA=`

In the image above, you can see our API-url in place. When you're done, press `Save changes`.
## Simulate Uplinks
Now, it is time to see how uplink messages to TTS (from your device) are forwarded to Ubidots. In your TTS-console, navigate to `Applications->End devices->your device -> Messaging`.

Enter `02 03` in the `Payload` field and press `Simulate uplink`. You should see a success-message indicating a successful simulation. Now, go to your Ubidots account and navigate to `Devices`. Woop woop, a new device!

And if you select it, you should see something like this:

This simply means that your Ubidots integration in TTS works! However, you probably have more interesting variables to visualize than `F Port`, `Frame Counter`, etc.. You will learn how to decode your payload in the next section.
## Ubidots decoder
In the [TTS](https://hackmd.io/5RbTAtCxTPu-hRi3k4p3dQ) tutorial, we left things off at transmitting data to TTS. Consider the code snippet below:
```python=
while True:
temperature = -23.3 # Your sensor value
humidity = 40 # Your sensor value
# > = big-endian
# h = Temperature (2 bytes, 16 bits, signed) Range: −32,768 to 32,767
# B = Humidity (1 byte, 8 bits, unsigned) Range: 0 to 255
payload = struct.pack('>hB', int(temperature * 100), int(humidity))
s.send(payload)
print('sent temperature:', temperature)
print('sent humidity:', humidity)
time.sleep(900) # wait 900 seconds (15 minutes) before sending again
```
When these two values are sent to TTS, the `MAC payload` looks like this:

The first two bytes (`F6 E6`) are the temperature bytes and the third byte (`28`) is the humidity byte. Here is why we chose one byte for humidity and two bytes for temperature:
The humidity value can span between 0 and 100 % and an appropriate datatype to use here is an `unsigned byte` (0-127).
As for the temperature, it can span (depending on the type of your sensor) from -60°C to 80°C. So we need a signed type. A signed type means that its values can be both positive and negative. We could use a `signed byte`, and that would probably suffice, but then we would only get the temperature as integer values, and not as floats. 23.3°C looks nicer than 23°C. So we use two bytes for temperature. Now, we can multiply our temperature by 100 before packing & sending it and divide it by 100 when unpacking/decoding our payload.
:::info
Notice that we're already multiplying our temperature by 100 during the packing in row 8 in the code-snippet above.
:::
So here is how you decode your payload:
In ubidots, navigate to `Devices->Plugins->Your plugin->Decoder` and replace the default `Decoding Function` with the following code-snippet and press `SAVE & MAKE LIVE`:
```javascript=
function format_payload(args){
var ubidots_payload = {};
// Log received data for debugging purposes:
// console.log(JSON.stringify(args));
// Get RSSI and SNR variables using gateways data:
var gateways = args['uplink_message']['rx_metadata'];
for (const i in gateways) {
// Get gateway EUI and name
var gw = gateways[i];
var gw_eui = gw['gateway_ids']['eui'];
var gw_id = gw['gateway_ids']['gateway_id'];
// Build RSSI and SNR variables
ubidots_payload['rssi-' + gw_id] = {
"value": gw['rssi'],
"context": {
"channel_index": gw['channel_index'],
"channel_rssi": gw['channel_rssi'],
"gw_eui": gw_eui,
"gw_id": gw_id,
"uplink_token": gw['uplink_token']
}
}
ubidots_payload['snr-' + gw_id] = gw['snr'];
}
// Get Fcnt and Port variables:
ubidots_payload['f_cnt'] = args['uplink_message']['f_cnt'];
ubidots_payload['f_port'] = args['uplink_message']['f_port'];
// Get uplink's timestamp
ubidots_payload['timestamp'] = new Date(args['uplink_message']['received_at']).getTime();
// If you're already decoding in TTS using payload formatters,
// then uncomment the following line to use "uplink_message.decoded_payload".
// PROTIP: Make sure the incoming decoded payload is an Ubidots-compatible JSON (See https://ubidots.com/docs/hw/#sending-data)
// var decoded_payload = args['uplink_message']['decoded_payload'];
// By default, this plugin uses "uplink_message.frm_payload" and sends it to the decoding function "decodeUplink".
// For more vendor-specific decoders, check out https://github.com/TheThingsNetwork/lorawan-devices/tree/master/vendor
let bytes = Buffer.from(args['uplink_message']['frm_payload'], 'base64');
var decoded_payload = decodeUplink(bytes)['data'];
// Merge decoded payload into Ubidots payload
Object.assign(ubidots_payload, decoded_payload);
return ubidots_payload
}
function decodeUplink(bytes) {
var decoded = {};
decoded.temperature = (bytes[0] << 24 >> 16 | bytes[1]) / 100;
decoded.humidity = bytes[2];
return {"data": decoded};
}
module.exports = { format_payload };
```
:::info
Notice the division by 100 in row 50 in the code-snippet above.
:::
To test your new decoder, navigate to `Applications->End devices->Your device->Messaging` and insert `FF E9 28` as your payload and press `Simulate uplink`. Now, if you go back to your device in Ubidots, you should see your temperature & humidity values. Just now, we simulated the uplink but the same would happen if you ran `main.py`.

Now that you have your sensor data available on Ubidots, let's create a dashboard! :D
## Create a Ubidots Dashboard
In Ubidots, navigate to `Data->Dashboards` and press `Add new Dashboard`. Now, it is your task to experiment with the settings to create a dashboard that best fits your needs.

Then, go ahead and click on `Add new Widget` and select the `Thermometer` widget.

Now, click on `Add variables` in the `Data` section in your thermometer and set the label to `temperature`. This connects the widget with your `temperature` variable in your Ubidots device. Do the same for your humidity value. Perhaps, use the gauge widget for humidity. Here are the results:

<br/>
:::info
**Credit**
Written by David Mozart
:::