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.

1 Like

HI all in the community. I’m actually stepping into the new world of JS. I’m bit familiar to industrial automation but this syntax is fully new for me. Actually I’m using CHATGPT to get my script syntax comùposed. After few apptempts and many reading in various Q&A topic I have to call for help since the script doesn’t seem to work. Due to lack of the syntax know how I have problems to troubleshoot and dig out the problem. I hope to get some help from here ans start learning curve

AIM of the script: making an floating average temperature calculation based on hourly measurements. Trough advanced flow the temperature value (as argument) is handed out to the the script and the returned number is the average of 24 last measurements. The call for the script looks like this:

My script actually looks like this:

//gem_temp_berekenen
async function onInit() {
  // Verkrijg de temperatuurwaarde uit de flow-argumenten
  const currentTemperature = flow.getArgument('averageTemperature'); // Zorg ervoor dat je het argument correct noemt in de flow

  // Voeg de nieuwe temperatuur toe aan de array
  temperatureArray.push(currentTemperature);

  // Zorg ervoor dat de array niet groter wordt dan 24 waarden
  if (temperatureArray.length > 24) {
    temperatureArray.shift(); // Verwijder de oudste waarde als er meer dan 24 waarden zijn
  }

  // Bereken het gemiddelde van de opgeslagen temperaturen
  const averageTemperature = temperatureArray.reduce((acc, temp) => acc + temp, 0) / temperatureArray.length;

  // Zet het resultaat in een nummer tag
  const numberTag = await Homey.apps.getApp('com.athom.homey.api').setTagValue({
    tag: 'average_temperature_tag',  // Pas de tag naam aan naar de tag die je wilt gebruiken
    value: averageTemperature
  });

  // Retourneer de gemiddelde temperatuur als resultaat
  return averageTemperature;
}

onInit();
// Beperk de array tot de laatste 24 waarden
if (temperatuurArray.length > 24) {
    temperatuurArray.shift();
}

// Bereken het gemiddelde
const gemiddeldeTemperatuur = temperatuurArray.reduce((a, b) => a + b, 0) / temperatuurArray.length;

// Sla de bijgewerkte array opnieuw op
await Homey.setGlobal('temperatuurArray', temperatuurArray);

// Retourneer de gemiddelde temperatuur
return gemiddeldeTemperatuur;

My global array variable to store the 24 temperature values has been defined in the global set.js

If I run the script the script in the advanced flow I get messages returned about the temperatuur array not defined. Many other variables are showing red colour (I have to assume this is also not OK??)

Two different names are used: temperatureArray and temperatuurArray.
according to the error description in line 29 !

Format for Tag: await tag('My Number', 123);

Better show your complete script.

Hi! Question: Can you only define one argument for a homeyscript?

It’s always one argument, but you can supply a JSON array of values, or just one value all in all:

1 Like