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.
It says Run “Code” but when you bring it into the advanced flow it shows as
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();
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.
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.
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”,
// 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; {
}
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.
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:
//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??)