HomeyScript: Any sane ways to use args?

Whenever you start a HomeyScript and pass it args, they’re all sent as a single string. So you have to use some sort of delimiter. I changed from using space to using #, since that’s less likely to occur.

So all scripts have to start with the boiler plate:

let myArgs = args.split('#');
let foo = parseInt(myArgs[0]);
let bar = parseFloat(myArgs[1]);

Anyone else have a better way of doing it?

1 Like

Hi @Articate,

I build the following function myself. Included in every Homey Script.

function getflowarg(arg) {
  const flow_args = JSON.parse(args);
  const arg_val = flow_args[arg]||"";
  if(arg_val != "") {
    return arg_val;
  } else {
    return false;
  }
}

Code example:

var arg1 = getflowarg('arg1');
if(!arg1) {
  // OPTIONAL ERROR ACTION
}
var arg2 = getflowarg('arg2');
if(!arg2) {
  // OPTIONAL ERROR ACTION
}

Flow argument example:

{"arg1":"value2", "arg2":"value2"}

I hope this helps you and others.
Happy coding :black_heart:!

2 Likes

A different approach: take look at the new app

1 Like

I have and enjoy that app. It’s a good way to create a core library of flows, like an error flow where you can send caller-flow, log group and error message, and even have a bool for if you want to get a notification for that specific flow. It’s nice. But using HomeyScript is also good, so I don’t want to replace a few lines of code with ten new cards.

On a similar line to @homeypro solution, but without needing to parse the args every time is to add the following as the first line of the script:
const flow_args = JSON.parse(args[0]);

then just use flow_arg.arg1, etc, to get the values.

You can also assign more meaningful names and use tags:

Notice the quotes around the Weather token as that is a string.

8 Likes

That increases readability and is equally many lines of code! I’m inclined to believe that that’s about the best we can do with how args are handled. Thanks for the help! And good stuff to you, too @homeypro!

1 Like

Thanks all and @Adrian_Rockall
Finally I found a way to pass multiple args to a script :tada: :pray:

1 Like

Personally, i like the method, but when there are quotes in the text, this will break!

Personally i prefer to just combine all arguments as one string and place a splitstring in it like [:;]

Within HS just split the string and read array as requested argumenttypes.

This will only ever break if the text within a string is the same as the splitstring, which could be maybe to be impossible.

But thats just because i prefer real bulletproof programming beter than readability. I guess it’s a choice.

Using common characters like : or ; as separator isn’t necessarily very bulletproof :stuck_out_tongue: At least use something that is very unlikely to occur in tags, like newlines, NUL, or :nail_care:t3:

1 Like

Please read carefully: I dont use a splitcharacter. I use a splitstring like exactly [:;].

All 4 characters are inserted between every argument.

I have never ever seen those characters in meaningfull sentences.

Ah, now I understand what you mean that you’re not going for readability :wink:

True!
I want a stable home, and usually, once i finish building flows, i hardly ever open/change them.

Also, i use my smartwatch app a lot, and with dutch sentences, qoutes are in it more than you would think.

Sure, I wouldn’t use JSON either (but I also wouldn’t use something like [:;]).

You find this not-readable?
image

Not really, no. Too easy to make mistakes, too.

True, and i need to keep the sequence and i need to manually convert argument types in HS.
But it gets the job done without ever creating a quote error.

As a senior developer, and someone who deals a lot with readability, I’d argue yours is the simplest way to do it, not a particularly readable way.

The problem here is that arguments can’t be split. Passing an array is silly, when we can never do anything but put an arbitrary string into the first element of the array. Now, HS’s inability to import code is in itself the crux of the whole thing. Code structure and maintainability goes out the window.

Over time I’ve removed myself from writing actually long scripts, and now I’m down to streamlining functionality that either has to be in code, or can remove like ten cards.

So, in our case, readability and maintainability needs to maintain a few things: How easy can I see what each argument is, how hard is it to make mistakes, and how does it appear as code?

I have an example that is:
Run script with arguments and return number:
Arguments:
Voltage, Power, Power, Power

I had to hover over each argument to see that the three “power” arguments were from 1) Power Target, a virtual sensor that has a Power value that’s how much power I can sustain for the rest of the hour 2) The total power used 3) the current power of charging my car.

With the rewrite, it now looks like this:
{“currentVoltage” : Voltage, “powerTarget” : Power, “totalPower” :Power, “chargingPower” : Power}

Now it’s a lot more readable. It also means that it’s straight forward to write the code:

let voltage = myArgs.currentVoltage;
let powerTarget = myArgs.powerTarget;
let totalPower = myArgs.totalPower;
let chargingPower = myArgs.chargingPower;

I could even simply use the myArgs.someArg in the code. This makes the boilerplate less prone to errors and easier to read and use. That makes maintainability better.

Also, wouldn’t JSON support using ’ to delimit strings, which means " would be fine in the strings? In the case of needing to solve that, you could do somethings different for those special cases. I doubt all your scripts need that ability. So you might be making your code too robust, which hurts readability and maintainability. I’d also suggest moving to using a repeating special character, like ### or something instead of [;:]. It takes way longer to write, and is obfuscating.

That argument seems moot, since JSON doesn’t support ' to delimit strings.

1 Like

Not so much moot as incorrect, I guess :sweat_smile: Couldn’t remember on the fly. Still seems worth it to either handle a string like that outside a JSON object, even like

{argument: 4}##otherArgument

and handle that.