Delete Variable data from Groups or Types of Devices

The following example shows HTML Canvas Widget implemented such that you can either, select or type a variable label, select a time window and then delete said data

Ubidots supports two types of grouping Devices: Device Types and Device Groups.

  • Create the structure. Paste the following in the HTML Code Editor Tab:

<p id="deviceLabelMessage"></p>

<div id="inputContainer"></div>

<form id="date-form">
	<label for="date1">Start date:</label>
	<input type="datetime-local" id="date1" name="date1" value="2023-01-01T00:00" required>
	<br>
	<label for="date2">End date:</label>
	<input type="datetime-local" id="date2" name="date2" value="2023-01-01T12:00" required>
	<br>
	<button type="submit">Delete values</button>
</form>

This will create the datetime selector, either the text-box or the drop-down menu to select the variable and the submit button.

  • Set the logic. Paste the following in the Javascript Tab:

var ubidots = new Ubidots;
var dashboardID;
var ubidotsToken;
var selectedVariableID;
var selectedVariableLabel;
var dashboardObject;
var inputContainer;
var displayedMsg;
var firstTime = true;


ubidots.on('ready', async function()
{
	//obtain the required variables
    dashboardID = ubidots.dashboardObject.id;
    ubidotsToken = ubidots.token;
	
	//get the dashboard object from ubidots api
    dashboardObject = await getDashboardObject(dashboardID, ubidotsToken);
	//get the element containing either the dropdown menu or the input text
    inputContainer = document.getElementById("inputContainer");  
	//get the elemente displaying the message
    displayedMsg = document.getElementById("deviceLabelMessage");
	//change the widget so it displays either a dropdown menu or an input type
    await setGUIAccordingToDeviceTypeFilter(dashboardObject, inputContainer, displayedMsg);
	firstTime = false;
	console.log("EXIT");
});

ubidots.on('selectedDevice', async function (data) 
{
	if(!firstTime)
	{
		//selectedVariableLabel = getVariableLabelFromContainer(inputContainer);
		deleteDropdownItems(inputContainer);
		await setGUIAccordingToDeviceTypeFilter(dashboardObject, inputContainer, displayedMsg);

		//populateDropdownItems(deviceVariables, dropdown);
		//displayDeviceData(deviceID, deviceLabel, token);
	}
});



document.getElementById('date-form').addEventListener('submit', async function(event)
{
	event.preventDefault();
	
	const ts1 = toTimestamp(document.getElementById('date1').value);
	const ts2 = toTimestamp(document.getElementById('date2').value);
	
	if(!assertTimestamps(ts1, ts2))
	{
		return false;
	}

	selectedVariableLabel = getVariableLabelFromContainer(inputContainer);
	console.log(selectedVariableLabel);
	
	const devicesInDashboardIDs = await getDashboardDevicesIDs(dashboardID, ubidotsToken);
	const req = await isTypesOrGroups(dashboardObject, deleteVariableFromGroup, deleteVariableFromGroup, devicesInDashboardIDs, ubidotsToken, selectedVariableLabel, ts1, ts2);
	console.log(req);
});

function populateDropdownItems(items, dropdownObj)
{
	var isFirst = true;
	items.forEach(function(item)
	{
		var option = document.createElement('option');
  		option.text = item.label + " : " + item.id;
  		dropdownObj.add(option);
		isFirst = false;
	});
}


function deleteDropdownItems(dropdown)
{
	while (dropdown.firstChild) 
	{
    	dropdown.removeChild(dropdown.firstChild);
  	}
}

function assertTimestamps(ts1, ts2)
{
	if(ts1 > ts2)
	{
		console.error("ERROR: end date being earlier than start date.", ts1, ts2);
		console.log("startDate: ", ts1);
		console.log("endDate: ", ts2);
		return false;
	}
	return true;
}

async function deleteVariableFromGroup(deviceID = [], ubidotsToken, variableLabel, ts1, ts2)
{
	const promisesList = [];
	await Promise.all(deviceID.map(async (id) => 
	{
  		const deviceVariables = await getDeviceVariables(id, ubidotsToken);
 		deviceVariables.forEach(async (variable) => 
		{
    		if(variable.label === variableLabel) 
			{
				const req = await deleteVariable(variable.id, ts1, ts2, ubidotsToken);
				promisesList.push(req);
    		}
  		});
	}));
	return promisesList;
}

async function isTypes(deviceID = [], ubidotsToken)
{
	console.log("ENTRY");
	return {"msg":1};
}

async function deleteVariable(variableID, ts1, ts2, ubidotsToken)
{
	var debugMsg = {"var id" : 0, "url": ".", "task id" : 0};
	const url = "https://industrial.api.ubidots.com/api/v2.0/variables/" + 
		variableID + "/_/values/delete/?startDate=" + ts1 + "&endDate=" + ts2;
	const response = await fetchWrapper(url, 'POST', ubidotsToken);
	debugMsg["var id"] = variableID;
	debugMsg["url"] = url;
	debugMsg["task id"] = response;
	return debugMsg;
}

function getVariableLabelFromContainer(container)
{
	var value = container.firstElementChild.value;	
	return value;
}

async function setGUIAccordingToDeviceTypeFilter(dashboardObject, inputContainer, displayedMsg)
{
    if(dashboardObject.context.deviceFilterType == 'device_type')
    {
        var a = await getDeviceVariables(ubidots.selectedDevice, ubidots.token);
        var labels = [];
        a.forEach(element =>
        {
            labels.push(element.label);
        });
    }
    isTypesOrGroups(dashboardObject, populateDropdown, populateTextField, inputContainer, displayedMsg, labels);
}

function populateDropdown(inputContainer, displayedMsg, dropdownElements)
{
    var dummyStr = '';
    dropdownElements.forEach(element =>
    {
        dummyStr = dummyStr + '<option value=\"' + element + '\">' + element + '</option>' + ' ';
    });
    inputContainer.innerHTML = `<select id="inputType">` + dummyStr + `</select>`;
    displayedMsg.innerText = "Select variable";
}

function populateTextField(inputContainer, displayedMsg)
{
	displayedMsg.innerText = "Enter a variable's label";
    inputContainer.innerHTML = `<input type="text" id="inputType">`;
}


function isTypesOrGroups(dashboardObject, typeCallback, groupCallback, ...rest)
{
    if(dashboardObject.context.deviceFilterType == "device_group")
    {
        return groupCallback(...rest);
    }
    else if(dashboardObject.context.deviceFilterType == "device_type")
    {
        return typeCallback(...rest);
    }
    else
        return {"ERROR" : "device filter type not recognized"};
}

async function getDeviceVariables(deviceID, token)
{
	const url = 'https://industrial.ubidots.com/api/v2.0/devices/' + deviceID + '/variables';
	const response = await fetchWrapper(url, 'GET', token);
	return response.results;
}

async function getDashboardObject(dashboardID, ubidotsToken)
{
    const url = 'https://industrial.api.ubidots.com/api/v2.0/dashboards/' + dashboardID;
    const req = await fetchWrapper(url, 'GET', ubidotsToken);
    return req;
}

async function getDashboardDevices(dashboardID, ubidotsToken)
{
    const url = 'https://industrial.ubidots.com/api/-/dashboards/' + dashboardID + '/devices?sort_by=name&page_size=500';
    const method = 'GET';
    const req = await fetchWrapper(url, method, ubidotsToken);
    return req;
}

async function getDashboardDevicesIDs(dashboardID, ubidotsToken)
{
    var req = await getDashboardDevices(dashboardID, ubidotsToken);
    var l = [];

    req.results.forEach(function(item)
	{
        l.push(item.id);
    });
	return l;
  
}

async function getDeviceObject(deviceID, ubidotsToken, filters = null)
{
	var url = 'https://industrial.api.ubidots.com/api/v2.0/devices/' + deviceID + '/';
	url = filters == null ? url : url + filters;
	const request = await fetchWrapper(url, 'GET', ubidotsToken);
	return request;
}

async function fetchWrapper(url, method, token = null, payload = null)
{
	const options =
	{
    	method: method,
		headers: {'Content-Type' : 'application/json'}
	};

	if (payload)
	{
    	options.body = JSON.stringify(payload);
  	}

  	if (token)
	{
    	options.headers['X-Auth-Token'] = token;
  	}

	const response = await fetch(url, options);
	const jsonData = await response.json();
	return jsonData;
}


function toTimestamp(date) 
{
	const dateObj = new Date(date);
	const timestamp = dateObj.getTime();
	return timestamp;
}

This implementation will display a different UI depending if the current Dashboard is set by Device Type or Device Group. In the first case, the variables common to the Device Type will be displayed in a drop-down menu. In the later, a text-box will be displayed for the user to type-in the label of the variable that wants to delete. The following GIF shows the Widget being used in both categories of dashboards:

Last updated