General Homey Script development questions

Hey all,

I’ve been playing with Homey Script for a few weeks now. Now, I’ve got a few general questions that I’ve bundled and wanted to ask. Some are probably rookie questions, so bare with me :slight_smile:

- My Questions
1. Why does Homey Script have code suggestions when the user has no permissions to run the code? For example await Homey.dashboards.getDashboards()
2. When the computer has been to sleep and you return to the Homey Script editor, the editor is unresponsive. Sometimes I forget that, do a bunch of code edits and save. The thing is it will not save your code, PLUS it gives no error. Result, loss of changes. Also you cannot run the code. I now, as a user, have to remember this bug and ALWAYS refresh the tab before continuing.
3. Homey Script shows typescript codehinting. So I assume I can add that. But when I add typescript it trows and error. (See screenshot)
4. Can Homey Script be edited externally? I find the code editor in the browser frustrating. I would prefer my preferred external IDE, like WebStorm. Is there a way to create/edit//delete this locally from an IDE?
5. I find the lack of import() frustrating.
I would wish to add node dependencies to scripts.
But more importantly. I wish to create custom methods and be able to use them in all HS scripts. I know I can get it though await Homey.apps.getApp({ id: 'com.athom.homeyscript' }) But that’s just fugly…
6. Can I extend my own methods to Homey? Like await Homey.myCode.writeOnTimeline()? Maybe one flow that runs on boot and in turn runs an init script to extend my custom code to the Homey Class?
7. As a fallback on 6. Can I do this with a custom app maybe?

HomeyScript isn’t meant to replace apps, or to provide a full features JS/TS environment, it’s meant to provide a just a bit more flexibility than regular flow cards. That’s why it’s are also intimately tied in with the flow system.

So TypeScript, remote editing, the lack of import()/require(), the lack of modules in general, etc, are all intentional.

If you want more, use the Web API (either from an app, or locally).

1 Like

Hi Robert or others,
I have this script and output, now I want to store the variables in a virtual device and that worked for me with my Qingping

However I am doing something wrong for my Eplucon (Ecoforest) Heatpump, since these variables do not appear in my flow as tags. What should I change?

This is the

// Login and get access token
var result = await fetch("https://portaal.eplucon.nl/api/v2/auth/login", {
  method: 'post',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    username: 'PASSWORD',
    password: 'PASSWORD'
  }),
});

if (!result.ok) throw new Error(result.statusText);

const body = await result.json();
console.log(body)

var access_token = body.access_token;
await tag("eplucon_access_token", access_token);

// Get the current date
const currentDate = new Date();

// Fetch statistics
const urlStats = `https://portaal.eplucon.nl/api/v2/econtrol/modules/1000704/statistics?range=day&day=${currentDate.getDate()}&month=${currentDate.getMonth() + 1}&year=${currentDate.getFullYear()}`;
const optionsStats = {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${access_token}`,
    'Accept': 'application/json'
  }
};

try {
  const responseStats = await fetch(urlStats, optionsStats);
  const dataStats = await responseStats.json();
  
  // Get the latest data point
  const latestDataStats = dataStats.data.data[dataStats.data.data.length - 1];
  
  // Create an object with the desired structure
  const output = {
    Binnentemperatuur: { value: latestDataStats.Binnentemperatuur },
    WW_temperatuur: { value: latestDataStats['WW temperatuur'] },
    Actuele_temp_DG1: { value: latestDataStats['Actuele temp. DG1'] },
    Brine_in_temperatuur: { value: latestDataStats['Brine in temperatuur'] },
    Brine_out_temperatuur: { value: latestDataStats['Brine out temperatuur'] },
    Heating_in_temperatuur: { value: latestDataStats['Heating in temperatuur'] },
    Heating_out_temperatuur: { value: latestDataStats['Heating out temperatuur'] },
    Buitentemp: { value: latestDataStats['Buitentemp.'] },
    Timestamp: { value: latestDataStats.created_at },
  };
  
  // Log the output
  console.log(output);
} catch (error) {
  console.error(error);
}

That result in this output in Homeyscript:

{
login: true,
access_token: ‘XXXXXXXXXXXXXXXXXXXXXX’,
error_code: 200
}
{
Binnentemperatuur: { value: 18.6 },
WW_temperatuur: { value: 47.3 },
Actuele_temp_DG1: { value: 27.1 },
Brine_in_temperatuur: { value: 6.4 },
Brine_out_temperatuur: { value: 6.2 },
Heating_in_temperatuur: { value: 30.3 },
Heating_out_temperatuur: { value: 27.1 },
Buitentemp: { value: 6.1 },
Timestamp: { value: ‘2024-01-22T21:20:00’ }
}

———————————————————
:white_check_mark: Script Success
:leftwards_arrow_with_hook: Returned: undefined

Not sure, but you still have to write (a) tag(s) for the value(s) you like to use in flows?

await tag ("Binnentemperatuur", latestDataStats.Binnentemperatuur);
2 Likes

Or return them as json tag, read then with json flowcards and place those in variables.

1 Like

Finaly, survived also my upgrade to Homey 2023… Slightly amended the script so that I can do what I want:

// Login and get access token
var result = await fetch("https://portaal.eplucon.nl/api/v2/auth/login", {
  method: 'post',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    username: 'USERNAME',
    password: 'PASSWORD'
  }),
});

if (!result.ok) throw new Error(result.statusText);

const body = await result.json();
var access_token = body.access_token;
await tag("eplucon_access_token", access_token);

// Get the current date
const currentDate = new Date();

// Fetch statistics
const urlStats = `https://portaal.eplucon.nl/api/v2/econtrol/modules/1000704/statistics?range=day&day=${currentDate.getDate()}&month=${currentDate.getMonth() + 1}&year=${currentDate.getFullYear()}`;
const optionsStats = {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${access_token}`,
    'Accept': 'application/json'
  }
};

try {
  const responseStats = await fetch(urlStats, optionsStats);
  const dataStats = await responseStats.json();
  
  // Get the latest data point
  const latestDataStats = dataStats.data.data[dataStats.data.data.length - 1];
  
  // Create an object with the desired structure
  const output = {
    Binnentemperatuur: { value: parseFloat(latestDataStats.Binnentemperatuur) },
    WW_temperatuur: { value: parseFloat(latestDataStats['WW temperatuur']) },
    Actuele_temp_DG1: { value: parseFloat(latestDataStats['Actuele temp. DG1']) },
    Brine_in_temperatuur: { value: parseFloat(latestDataStats['Brine in temperatuur']) },
    Brine_out_temperatuur: { value: parseFloat(latestDataStats['Brine out temperatuur']) },
    Heating_in_temperatuur: { value: parseFloat(latestDataStats['Heating in temperatuur']) },
    Heating_out_temperatuur: { value: parseFloat(latestDataStats['Heating out temperatuur']) },
    Buitentemp: { value: parseFloat(latestDataStats['Buitentemp.']) },
    Timestamp: { value: latestDataStats.created_at },
  };
  
  // Create tags from the output object
  for (let key in output) {
    await tag(key, output[key].value);
  }
  
  // Return the output
  return output;
} catch (error) {
  console.error(error);
}


1 Like

I will have an Eplucon system soon as well: heat pump, solar and wtw. Would be cool if an app for homey is created. Unfortunately I am no app developer. :weary:

1 Like

FYI Jacco, you can request for apps by following this guide here

1 Like

I have another script question of my own:
I am a newbie in scripting, but have tried to just use the sample example-fetch.js as a base and just modifying it to fit my API, as a test.
However my heat pump api response is in this format:

{
	"0002": 2000,
	"1221": 1,
	"0219": 300,
	"4101": 0,
	"1A05": 35,
	"1A20": 16,
	"CFAA": 2387
}

Ad for some reason the script does not seem to accept numeric keys in the body.xxxxxx structure?
So if I ask for the
log(${body.021});
it will fail, but if I instead ask for the only alphanumeric value in the output,
log(${body.CFAA});
it will return the correct value.

It seems I am missing some basic js understanding here.
Can someone be nice an help out?

The whole script is:

// Create the request

const res = await fetch(‘http://192.168.1.239/api/alldata’);

if (!res.ok) {

throw new Error(res.statusText);

}

// Get the body JSON
const body = await res.json();

//log(${body.liveBuild.name.en} (${body.id}) v${body.liveVersion});

log(${body.0219});

If you want to use purely numerical object keys, you need to pass them as a string explicitly, which means using object["key"] syntax:

log(body['0219']);

(similarly, body.CFAA is equivalent to body['CFAA'])

2 Likes

Thanks a lot Robert!

Wout,
Nice to see that you got the eplucon thermostat working.
Could you perhaps describe how you did this?
So a kind of walkthrough, I’m a novice in the field of APIs and scripts.

Thank you

@Lindhardsen see the full guide here for the Eplucon Ecoforest Heatpump app for Homey

1 Like

Hi Wout, is this read only or are you also able use Homey to change settings of the Heatpump, like On/OFF, setting temprature of te Boiler, or adjusting the weekly schedule for heating and tap water to match the de day low prices. I currently use smart plugs to switch my Techcontrollers, which manage the underfloor heating distributors, on or off depending on the heat demand and actual electricity price.

I replied in the Eplucon topic (nice requirements)

Hi,
not a that high-class questions as all the other posts, but then again…

I´m trying to shorten the above text tag by running a homey script in a flow. The script is meant to return a text-tag and is::

// My Code neu

let input = (args[0]);

let result = “”;

let stelle = 0;

if (input.match(/;/) = null) {

input = (args[0]);

}

else {

result = input.substring(0,input.search(/;/));

}

return(result);

However, an exception is thrown:
———————————————————
:x: Script Error
:warning: TypeError: Cannot read properties of undefined (reading ‘match’)
at Test.js:7:11
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
{“message”:“Cannot read properties of undefined (reading ‘match’)”

What do I do wrong?

First make sure not to use fancy (double) quotes

Use this

"

Thanks and agreed - I also changes the if-statement to “==” instead" of “=”, but both didn´t change the exception…

The error is actually pretty clear: on line 7 of your script, you’re trying to call a method .match() on something that is not defined.

Line 7 is this:

if (input.match(/;/) = null) {

Which means input is not defined.

What’s input?

let input = (args[0]);

So args[0] is not defined.

What’s args[0]?

it’s the first argument provided to the script.

In other words: you’re calling the script without a required argument.

Thanks, that´s what I assumed, too.

This is the respective flow:

So, my understanding is that ht script is called with “Ereignis”, which then again should be processed by the script.
But most likely, the first if flow card doesn’t hand anything over to the flow.
Are tags available inside “local” scrips, and if yes, how?
This is the one I need, then:
image