Hi all!
I have been playing around with a few things that I feel aren’t very well documented but are extremely powerful; using widgets to directly call analyses, accessing the widget’s data within that analysis and changing device tags dynamically. I’ll give some step by step instructions, commented sample code and some additional notes so you hopefully need to dig less to learn what I did!
What you’ll learn:
Goal: In a blueprint dashboard, use an “Input Form” widget to edit the value of a device’s single Tag without modifying the others.
Step 1: Widget
Step 2: Analysis
See the commented code below. //A and such are explained below.
/**
* Update the value of a Tag without affecting others
*/
const { Account, Analysis, Device, Utils, Services } = require("@tago-io/sdk");
async function updateTag(context, scope) {
// Requires scope to know what device and what widget called it
if (!scope[0]) throw "Scope is missing";
// Read the stored account_token and make an account object
const env_vars = Utils.envToJson(context.environment);
const account = new Account({ token: env_vars.account_token });
// Get the device id of the caller
const {origin} = scope[0]
// Get the new tag value from the widget. Change "VARIABLE_NAME" to match that within the input form.
const new_tag = scope.find(x => x.variable === 'VARIABLE_NAME');
// Get the device's info using its ID, then isolate the tags
const device_info = await account.devices.info(origin);
var tags = device_info.tags;
//A
//B1
// Search for the Tag Key you want to edit "KEY_NAME"
let i
for(i = 0; i < tags.length; i++){
// Find the Key/Value pair you want to edit
// C
if(tags[i].key == "KEY_NAME"){
//B2
// Set the VALUE of the pair you want to edit to the one provided by the input form
tags[i].value = new_tag.value;
break;
}
}
// Push the new set of tags to the device. You're done!
account.devices.edit(origin, { tags });
//C
}
module.exports = new Analysis(updateTag);
Some notes and optional things:
You must have your account_token within environment variables
A. To only add a new Tag without changing existing ones, I believe you can use this here and skip the following loop:
tags.push({ key: "KEY_NAME", value: new_tag.value });
B. You can declare a variable at B1 and set it to tags[i].value at B2 if you want to save the old Tag value.
C. If you are changing multiple Tags, make sure you check for all Keys and do not break after setting the value.
if(tags[i].key == "KEY_NAME"){
tags[i].value = new_tag.value;
}
else if(tags[i].key == "KEY_NAME2"){
tags[i].value = new_tag2.value;
}
D. You can push old and/or new Tag values saved in step B to your device’s bucket using…
const device_token = await Utils.getTokenByName(account, origin);
const device = new Device({ token: device_token })
var data =
[
{
variable: "tag_old",
value: variableDeclaredAtB1
},
{
variable: "tag_new",
value: new_tag.value
}
]
try {
await device.sendData(data);
context.log("Inserted " + data[0].value + " " + data[1].value);
} catch (error) {
context.log("Error when inserting:", error);
}
In the past I would have had the widget ‘Send to Bucket’ and then have an action trigger the analysis on variable update. This method stores 1 less variable in your device and has 1 less action, helping reduce clutter throughout your Tago backend.
Hopefully these steps helped someone, I’d appreciate any feedback.
Referenced community posts: