CESVA's TA120 sensor is a noise measuring sensor for smart solutions. The TA120 sensor combines the precision of a Class 1 sound level meter, the protection of an outdoor kit, and full connectivity with CESVA NoisePlatform and open-source platforms.
In this article you'll learn how to set up your TA120 and use an UbiFunction to parse the UltraLight 2.0 communication protocol's response so that the TA120's data can be sent to an Ubidots device.
Requirements
Active Ubidots account
At least one UbiFunction (if you don’t have one yet, follow this article first)
1. Ultralight 2.0 Communication Protocol
CESVA provides various methods for connecting the device to the internet and facilitating HTTP requests, utilizing communication protocols optimized for low power consumption and limited bandwidth. These protocols include UltraLight 2.0 and Sentilo JSON Format.
Ultralight 2.0 is a lightweight text-based protocol aimed at devices and communications where the bandwidth and the device memory may be limited resources. Within the CESVA Sensor Manager software, you can configure and select the communication protocol to make HTTP requests.
In this link you can download CESVA TA120 protocol's structure, including UltraLight 2.0 and Sentilo JSON Format.
2. Creating a Raw UbiFunction
By default, an UbiFunction exclusively accommodates the application/JSON content Type. However, it's important to note that not all communication protocols rely on this specific format for transmitting data.
In scenarios where alternative formats are employed, you have the option to toggle the Raw Function feature within your UbiFunction, as seen in the image below. This action allows you to receive data coming in any format, and parse into an Ubidots compatible format.
Follow this article for any additional information about Raw Functions features.
You need to select a POST Method and a Runtime Python 3.7. After making live the function, copy the HTTPS Endpoint URL.
The complete code is provided below for your Raw UbiFunction. Simply ensure that you copy and paste it into your UbiFunction for seamless implementation.
import time
import requests
from datetime import datetime
from urllib.parse import urlparse, parse_qs
BASE_URL = "https://industrial.api.ubidots.com"
LABELS_MAP = {
"n": "lat_sound_presure_level",
"o": "lat_overload",
"u": "lat_underrange",
"s": "la1s_registers",
"ef": "extra_functions_name",
"en": "extra_sound_presure_level",
"eo": "extra_overload",
"eu": "extra_underrange",
"es": "extra_1s_registers",
"b": "battery_level",
"p": "power_supply_status",
"w": "wifi_strength",
"m": "modem_strength"
}
def main(args):
print(f"Arguments is: {args}")
# Define the payload
payload = parse_and_build_payload(args["body"])
# Define query parameters
parsed_query_params = parse_path(args["path"])
token = parsed_query_params["k"][0]
device_label = parsed_query_params["i"][0]
dt = parsed_query_params["t"][0]
timestamp = int(datetime.fromisoformat(dt[:-1]).timestamp() * 1000)
# Send data
res = send_data(device_label, payload, token, **{"timestamp": timestamp})
print(res, res.json())
return {"status": "Ok"}
def parse_path(path):
parsed_result = urlparse(path)
dict_result = parse_qs(parsed_result.query)
return dict_result
def parse_and_build_payload(body):
split_data = body.split("|")[1:]
payload = {}
for i in range(0, len(split_data), 2):
label = LABELS_MAP[split_data[i]]
value = float(split_data[i+1])
payload[label] = value
return payload
def send_data(device, payload, token, **params):
url = f"{BASE_URL}/api/v1.6/devices/{device}"
headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
res = make_request("post", url, headers=headers, params=params, json=payload, max_attempts=5)
return res
def make_request(
method,
url,
headers=None,
max_attempts=5,
params=None,
data=None,
json=None,
timeout=10
):
attempts = 1
kwargs = {
"method": method.upper(),
"url": url,
"headers": headers,
"params": params,
"data": data,
"json": json,
"timeout": timeout
}
try:
req = requests.request(**kwargs)
status_code = req.status_code
time.sleep(1)
while status_code >= 400 and attempts < max_attempts:
req = requests.request(**kwargs)
status_code = req.status_code
attempts += 1
time.sleep(1)
return req
except requests.ConnectionError as e:
print(f"Error de conexion: {e}")
return None
except requests.Timeout as e:
print(f"Connection timedout: {e}")
return None
except Exception as e:
print("[ERROR] There was an error with the request, details:")
print(e)
return None
3. Configuring the TA120 sensor
For the initial step of configuring the TA120 sensor, it is necessary to download the CESVA Sensor Manager Software by following the provided guide. This software facilitates the configuration of all CESVA sensors for data transmission to various server connections.
With the CESVA Sensor Manager software, you can configure the follow parameters for the server connection:
Protocol: HTTP protocol. Options: UL 2.0, Sentilo or CESVA.
Security: server security (HTTP or HTTPS).
Host: server for data transmission. Name of your API domain.
Port: number of server port. Defaults to 80.
LinkData: name of your API path.
Token: the value of your API key to set a server connection.
TLeq: select the integration time T.
Overload/underrange: Activate or deactivate to send Overload and Underrange.
Extra function: Select one of the following functions: LCT, LAFmaxT, LASmaxT.
LAeq1s: activate or deactivate to send LAeq/extra function 1s registers.
The image below shows a basic setup of the CESVA Sensor Manager.
You need to configure the following fields:
Protocol: UltraLight 2.0.
Token: Your account's token.
LinkData: /prv/<username>/<function_name>
CESVA will initiate a POST request to the designated host, following its corresponding header and body specifications.
4. Receiving data in Ubidots
Once you have activated the function in your account and successfully connected it to your CESVA TA120 sensor, you can expect to observe an output similar to the following within the function's logs.
Here is the input data received from your sensor manager:
2023-08-30T13:34:52.632667Z stdout: Arguments is: {'body': '|n|034.8|o|0|u|1|b|8|p|0|m|0\r\n', 'headers': {'connection': 'keep-alive', 'content-length': '30', 'content-type': 'text/plain; charset=UTF-8', 'host': 'parse.ubidots.com'}, 'path': '/prv/<username>/cesvat120?k=BBFF-DnrBpricV9PizIS3Um3NyYRi5jUt0L&i=TA120-T255615&t=2023-08-30T01:04:51Z&getCmd=1'}
Here you can see the output after parsing the data and transforming it into a compatible JSON Ubidots format.
2023-08-30T13:34:52.632817Z stdout: <Response [200]> {'battery_level': [{'status_code': 201}], 'lat_overload': [{'status_code': 201}], 'lat_sound_presure_level': [{'status_code': 201}], 'lat_underrange': [{'status_code': 201}], 'modem_strength': [{'status_code': 201}], 'power_supply_status': [{'status_code': 201}]}
In the image below, you can see the device created within the UbiFunction, along with the raw variables that have been generated after parsing the input data.