Changing Device Tags With Widget

Changing Device Tags With Widget

@Andreas Gudmundsson

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:

  • How to modify existing tags and create new tags in a analysis
  • How to trigger an analysis using an input form WITHOUT an action
  • How to use scope to identify the device and widget relevant to the current run

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

  • An input form with any field type (I used dropdown). The variable name(s) can be anything; it will only be used within the analysis and not stored.
  • The ‘Value’ will be what your Tag’s value is set to
  • Change the ‘Submit’ buttons ‘When clicked’ settings to ONLY Run Analysis. At this point, you need to create the Analysis that we will implement and select it.


image

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:

    • Gave an overall tag editing procedure
    • Helped me use scope properly (I’ve almost only used it in 1 way before)