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