Piston External URL value available to self


Is it possible for the piston to know its own External URL in a local variable? I looked in the smartApp and see it developed under the state.endpoint and used in the html piston.module.html. However, I do not see it exposed to the piston itself.

Hoping to send this value by a POST to an another system to allow for auto registration.


Even if it doesn’t know it natively, it is easy to copy/paste it inside the piston.


Thanks. That is my current workaround solution. Was hoping for something a little more elegant just to be fashion forward. I will dig into the source and submit a pull request to webCoRE if this is a trivial patch solution.


Well, for what it’s worth, a piston should never send any commands to an outside source unless we specifically program that logic in that piston. It is not safe or wise for all pistons to blindly send a sensitive link to anyone that requests it.

This means that for a piston to send out a URL link, you have to actually write the code for it anyways… So why not just include that private link in your coding. It takes no extra work, but is infinitely safer that what you are asking.

Maybe I am overly security conscious, but I will never update my webCoRE if your suggestion is added to the base code.


Let us just pretend for a moment I like sharing my pistons with others on this forum. Your nifty suggestion (that didn’t answer my question BTW) would be do to this:

The reason I would like to have a global variable within the piston definition would to be able to do something like this (if you could replace ‘$random’ with lets say ‘$externalURL’):

On the bad example, not only do you see my external url, if you import the piston you will then actually import my piston external url. By giving a $reference that your piston can source directly does not decrease your security any more or less beyond what was already given the webpage link reference.

I do appreciate your passion on security concerns and hope you do update webCoRE often, when others take the time to work on the source. However in all honesty I probably won’t patch this, because I finished the piston and it works fine and have other more pressing things todo than argue this point.


One more trick that may be helpful…

If you are sharing a piston with a private URL…

  • If the URL is a variable in the define section, it will be exposed (visible) to everyone…
  • If the URL is in the body of the piston, it will be anonymized…
  • If the URL is stored in a global variable, it will also be anonymized…

… So at least you have choices


Thanks - didn’t know a URL in the piston body would anonymize. I did spend some time this morning and added $endpoint and $randomUUID. Actually pretty simple to add system variables the way things are designed.

Both updates are in the “webCoRE Piston” SmartApp.

Add the following at line 7980 in the getSystemVariables() function below temperatureScale:

private static Map getSystemVariables() {
	return [
        '$args': [t: "dynamic", d: true],
        "\$temperatureScale": [t: "string", d: true],
        "\$endpoint": [t: "string", d: true],
        "\$randomUUID": [t: "string", d: true]

And then add the following at line 8034 in the getSystemVariableValue() function below temperatureScale:

private getSystemVariableValue(rtData, name) {
	switch (name) {
    	case '$args': return "${rtData.args}".toString()
        case "\$temperatureScale": return location.getTemperatureScale()
        case "\$endpoint": return "${parent.state.endpoint}execute/${hashId(app.id)}".toString()
        case "\$randomUUID": def result = getRandomValue("\$randomUUID") ?: UUID.randomUUID().toString(); setRandomValue("\$randomUUID", result); return result

Save and then publish to self.

@ipaterson I will submit a pull request to the master. If these changes are too controversial I can just hack on any future releases. They both come in handy when building functions to interface with AWS Lambda functions to self register callbacks.

Here is a test piston.


Thank you for following through! If you do get that PR in this week (against dev please rather than the master branch) it will definitely be included in the next update. An important change to combat the rising instability of the ST groovy platform will be ready to test soon so I would love to include this in that release.


You got it. Pull #87.


Closed #87. Pull #88 against dev.


So what is randomUUID for?

In HE, end points can be either local or cloud (if you are giving it to someone external, they would need the cloud endpoint), otherwise local is better to avoid anything leaving the local network.

The other concern is this is one of the few variables that calls the parent to resolve. This means on piston startup the parent gets called yet again (slows stuff down). In general it would be better to treat this like variables that are read from rtData to avoid the parent call on piston startup (and then in getVariable, it would need to have the parent call if someone actually uses it.)


Can’t say I am the best groovy guy out there, but can hold my own against any C++ engineer. And calling a pointer like parent is about the fastest thing you can do; and even works within an ISR request. What am I missing here that gives pause this is would slow down?

And agree - local is better than cloud. I am just passing the same URL that allows for piston access if you cut and paste from the weblink. WebCoRE is nothing more than a really fancy flexible SmartApp running in the ST cloud like any other SmartApp (exception to Smart Lighting) and this is the only access your are allowed as written today. Even if you had a local hub listening to port 39500 it just relays out to the ST cloud for processing. At least with the external URL current method you can use https and DNS which is more secure than a listener on your local net. Also, the local solutions have problems with using a DNS name (unless you get creative with external DNS to local IP) and CORS problems with JavaScript.

Would think randomUUID self explains itself as to purpose.


Calling parent to have it access state adds makes 2 apps have to load state on startup. On HE, I have removed this at the 99th percentile as the more than doubles startup time.

I’m not suggesting you don’t add the variables, I’m suggesting you do it via rtData, and then in getVariable() you have that method load from the parent if not already loaded.

In general getSystemVariablesValues() does not call parent activities on HE as it gets loaded on every piston startup (whether variable is used or not).

So I’m not commenting on your idea, just your implementation.


Starting to make sense on your discussion here. It is the access to state that has start delays since it would need to be brought back from persistent memory which I assume is a non-sql DB or something to that design. Will look at your suggestion.


Thanks for looking into that improvement, and thanks @E_Sch for reviewing the pull request.


@E_Sch see any concern with the following change to getVariable()?:

    	} else if (name.startsWith('$incidents[') && (name.size() > 11)) {
        	result = getIncidents(rtData, name.substring(10))
        } else if (name == '$endpoint') {
            result = [t: 'string', v: "${parent.getEndpoint()}execute/${hashId(app.id)}".toString()]
        } else {

Then updated getSystemVariableValue() to:

	case "\$temperatureScale": return location.getTemperatureScale()
	case "\$endpoint": return "${rtData.endpoint}".toString()
	case "\$randomUUID": def result = getRandomValue("\$randomUUID") ?: UUID.randomUUID().toString(); setRandomValue("\$randomUUID", result); return result

It checks out on unit testing and probably better since it does hide the URL from an accidental screen shot post. If good I will update the pull request @ipaterson


This is the right idea - I would need all the code to do a proper review.

Note the syntax for the getSystemVariableValue() is a bit convoluted.

You might just fill in rtData.endpoint in your first use…(Similar comment for your first use…)

You could just use return (String)rtData.endpoint

toString() is expensive in groovy…


Tried that the first time (didn’t know it was expensive BTW) but it didn’t cast the null so the $endpoint would show up in the System variables list. Took a moment to figure it out.

@ipaterson pull #88 on dev updated.