How to run Homeyscript from an Advanced Flow with Args[]

I started a new topic as all the ones I searched for are quite old. If this should be posted elsewhere please advise.
I have written a Homeyscript and saved it in the Homeyscripts tab “</>”. I have pasted it below.
I need to run it with 2 dates (startdate, enddate) and have it return a number (number of minutes)
I am a bit confused which flow card to use. Some seem to run the code as it has been saved in </> while others bring up an editor for you to enter the code into. I don’t understand this nuance.
Screenshot 2024-03-27 at 2.04.13 pm
It says Run “Code” but when you bring it into the advanced flow it shows as
Screenshot 2024-03-27 at 2.05.38 pm
And it seems the only card you can use that returns a card.

Here is my code. It tested OK, but I would also appreciate someone casting their eye over it in case I have committed some crime. I am very new at writing Homeyscript.

const apiKey = 'psk_f31a4b0b3ee67b8db63067a7d0385bd0';
const siteId = '01H92N0GC70BAZHM48P2C52J3M';

let startDate = args[0]; // replace with your start date
let endDate = args[1]; // replace with your end date

// let startDate = '2024-03-27'; // replace with your start date
// let endDate = '2024-03-27'; // replace with your end date

let calculateDuration = async () => {
    const response = await fetch(`https://api.amber.com.au/v1/sites/${siteId}/prices?startDate=${startDate}&endDate=${endDate}&resolution=30`, { 
        headers: { 
            'Authorization': `Bearer ${apiKey}` 
        } 
    });

    const data = await response.json();
    
    // Get the current time in UTC and adjust for AEST (GMT +10)
    let currentTime = new Date();
    currentTime.setHours(currentTime.getUTCHours() + 10);
    currentTime = currentTime.toISOString().split('T')[1].split(':')[0];

    // Filter the data to only include intervals after the current time
    let positivePerKwhIntervals = data.filter(item => {
        let itemTime = item.intervalStart ? item.intervalStart.split('T')[1].split(':')[0] : null;
        return item.channelType === 'feedIn' && item.perKwh > 0 && itemTime >= currentTime;
    });
    
    let totalDurationInMinutes = positivePerKwhIntervals.length * 30; // since each interval is 30 minutes long

    log(`Total duration for which the price will be negative is ${totalDurationInMinutes} minutes.`);
    return totalDurationInMinutes;
};

return await calculateDuration();

Ok, I have been trying to find more info in posts about this topic. I now understand that if you want to run Code (the top two options when selecting the Homeyscript card) then you can’t have Args. Correct?
And if you want Args then you have to use run //MyScript. I have got this working for some of the Homeyscript I’ve written but not all.
I saw a HomeyScript which used global.get and global.set commands so I thought I could use them. They don’t raise an error when I run them but the value assigned is Null so it looks like they are not working. There are examples in the Homeyscript .js list but I can’t get even these simple ones to run.
Can anyone help me work through these issues please.
It will require me to share my code and have someone explain how to make it work to achieve what I am trying to do. The script modified below is working when I test it. I just need to work out how to run it from an Advanced Flow.

const apiKey = 'psk_f31a4b0b3ee67b8db63067a7d0385bd0';
const siteId = '01H92N0GC70BAZHM48P2C52J3M';

let calculateDuration = async () => {
    const response = await fetch(`https://api.amber.com.au/v1/sites/${siteId}/prices/current?next=20&previous=0&resolution=30`, { 
        headers: { 
            'Authorization': `Bearer ${apiKey}` 
        } 
    });

    const data = await response.json();
    
    // Filter the data to only include intervals where the spot price is negative and the interval has not ended
    let positivePerKwhIntervals = data.filter(item => {
        return item.channelType === 'feedIn' && item.spotPerKwh < 0 && new Date(item.endTime) > new Date();
    });
    
    let totalDurationInMinutes = positivePerKwhIntervals.length * 30; // since each interval is 30 minutes long

    log(`Total duration for which the price will be negative is ${totalDurationInMinutes} minutes.`);
    return totalDurationInMinutes;
};

return await calculateDuration();

On my.homey.app, create a new script using the </> button in the sidebar:

Then you can use it with the “Run script” or “Run script with argument” cards in an advanced flow.

I have no idea what global.get()/global.set() have to do with this, but it sounds like you’re misunderstanding their purpose (they can’t be used to get/set Homey variables).

Thanks Robert. Aah, I just reread the example. It is to set Homeyscript variables not Flow variables. My bad.
I have been keeping reading and have now got this done using:
await Homey.logic.updateVariable({id:'e4127f78-5012-4890-b662-7bbdeb0ecea9', variable: {value: cState}})

Can you call a Homeyscript program from within another Homeyscript? When I try it tells me it is not defined.

No.

You can only really have one args as far as I’m aware, so what I do is I usually construct some json, and then call JSON.parse(args[0]) to get the values.


Thanks Stefan. I assume that as you are passing Args then all of your javascript is imbedded in the Homeyscript card?
It looks like you are passing 3 Args so wouldn’t you be able to reference them in your code as Args[0], Args[1] and Args[2] ? Although your solution using JSON.parse looks good. I’ll use that.

No, they made a Homeyscript (using the button I showed a few posts ago) called enery-price.js, and the card calls that script.

No, it’s one argument that consists of a JSON string.

Could you share that post Robert. I have looked under your activity and done a search but I can’t find it.

Just scroll up:

Thanks for continuing with me here.
I must still be doing something wrong. I have written the Javascript and saved it and then tried to run it with the Run script with Argument returning a Yes/No-Tag. But it errors with “Variable not defined”,
Screenshot 2024-04-04 at 3.02.53 pm

// This code checks the value of a variable, then delays by delayTime and then checks the value of the variable again
// This allows the filtering of spikes in data which happens often in the Tesla Gateway
let delayTime = 5000;
//Parse arguments
let {variable, value} = JSON.parse(args[0]);
 if (variable > value) {
  // Wait for delayTime
  const startTime = Date.now();
  while (Date.now() - startTime < delayTime) {
    // Wait
    }
    // This code will run after the delay
    if (variable > value) {
      return true;
    }}
    else {
      return false;
    }
return false; {
}

You’re mixing things up.

There are two types of card: “Run Code” and “Run Script”.

You’re using the “Run Code” card, where you have to enter the actual code in the editor that is shown in your screenshot.

I’m suggesting to use the “Run Script” card, where you create a script file, and you can choose the file to run.

Either that, or add the actual code to run in the “Run Code” card (which is a bit easier since it will automatically “convert” a return value into a Yes/No tag, which is a bit more difficult to do with the “Run Script” card).

Also, your script it flawed as it uses a “busy wait” to implement the delay. Instead, you need to use the wait function to implement delays (or just implement the delay in your flow rather than in the script).

Thanks Robert. I will use that. There is a reason I want to do it in script although it’s hard to explain and my issue may be a symptom of something else I’m doing wrong.

And I get it now, must be my age. I was looking (expecting) the Run Script cards to be together so I was trying to work out how you could Run Script with Arguments. Then I found it, right down the bottom. And using this method I will need to use this method to set the Yes/No variable.
await Homey.logic.updateVariable({id:'5d153b3f-fb7d-45f0-9040-a34e5cc062ab', variable: {value: preserveState}})
Thanks again for your help. I was getting very confused.