webCoRE for Hubitat Updates

Tested on staging.webcore.co and it is working again. Thanks much.

1 Like

adding a setLevel() device command in a webCoRE piston is not allowing the optional duration parameter.

the setLevel() device command should accept the 1st parameter as a numeric level from 0-100 and an optional 2nd parameter as a numeric duration. This is a hardware fade that is performed in the dimmer switch firmware (not the webCoRE software emulated "Fade level")

The underlying piston code seems to be able to accommodate multiple parameters but the UI only allows a single parameter with no provision to enter optional parameters.


image

I have attempted to modify the HE webCoRE Apps Code so it allows for the optional 2nd parameter. I edited line 3462 as follows (bold italic is the added code):

setLevel : [ n: "Set level...", i: 'signal', d: "Set level to {0}%{1}{2}", a: sLVL, p: [[n:"Level",t:sLVL], [n:"Duration",t:sINT,r:[0,8192],d:" with duration {v}"], [n:sONLYIFSWIS,t:sENUM,o:[sON,sOFF], d:sIFALREADY]], ],

that change now lets me add an optional 2nd parameter.


image

HOWEVER, the command does not execute. Nothing. I was hoping this was just a simple bug in the UI where the optional 2nd parameter was just overlooked or forgotten. But when I enter the 2nd parameter, the command does not execute. If I remove the 2nd parameter then setLevel(x) works again. So I guess there is something else in the piston code that I'm missing. That code looks like a fairly generic wrapper for the executePhysicalCommand() and accepts a "params" list variable. So I'm lost as to where it is choking on the 2nd parameter for the setLevel(x,y) device command.

Any ideas?

I'll work on a fix. It is a bit more complicated than what you tried.

There are also issues of backward compatibility and not breaking existing pistons.

Should have it later today.

1 Like

Awesome and thanks! :smiley:

Note that I arbitrarily put a range of r:[0:8192]. You probably don't want to use that. I think it might vary with different dimmer brands so probably needs to be loosely bounded. Maybe just leave the range off (although it probably should be restricted to positive values only :thinking:)

New Release posted today.

See note 1 for release updates info

Do note to clear your browser cache after updating.

  • loading a small piston first makes the db update for the browser go quicker.
1 Like

I appreciate you fixing this so quickly :+1: However, in my humble opinion, the fix has some bugs that need attention. :blush:

In the webCoRE main code, it now accepts the optional "duration" parameter. That is good. But it doesn't display the value in the editor. This is mostly a cosmetic bug because the command does seem to work with the duration setting even though it doesn't show it in the editor.


image

Here is my suggestion to fix the code:
Line 3462 you have:

setLevel: [ n: "Set level...",i: 'signal',d: "Set level to {0}%{1}",a: sLVL,p: [[n:"Level",t:sLVL], [n:sONLYIFSWIS, t:sENUM,o:[sON,sOFF], d:sIFALREADY],[n:"Transition duration (seconds)", t:sINT]], ],

I suggest changing it to this:

setLevel: [ n: "Set level...",i: 'signal',d: "Set level to {0}%{2}{1}",a: sLVL,p:[n:"Level",t:sLVL], [n:sONLYIFSWIS, t:sENUM,o:[sON,sOFF], d:sIFALREADY],[n:"Transition duration (seconds)", t:sINT, d:" in {v} seconds"]], ],

That will make it display like this:
image

Also, in the webCoRE-Piston code, it appears that you re-used the global 'delay' variable to hold the local 'duration' value. I think this could be a problem for people who use the Piston Execution Delay option. I'm new to the webCoRE code, so I may be interpreting this wrong. But I believe the global 'delay' variable is used across multiple commands to specify a delay in milliseconds between command executions and you don't want to over-write it with the setLevel 'duration' value. The global 'delay' value is a Piston Execution Setting found here:

On lines 3417-3421 you have:

Long delay=psz>2 ? (Long)params[2]:0L
if(attr==sSTLVL && delay>0){ // setLevel takes seconds duration argument (optional)
List larg=[arg, delay.toInteger()]
executePhysicalCommand(rtD,device,attr,larg)
}else executePhysicalCommand(rtD,device,attr,arg, delay)

That causes the global piston execution 'delay' variable name to get replace with the setLevel variable params[2] (transition duration) and that will bypass any global piston execution delay that may already be set.

My suggestion is to create a local 'duration' variable name instead of using the global 'delay' name. Then you can pass in the optional duration value as well as the global delay value and also preserve the piston delay for non setLevel commands

Long duration=psz>2 ? (Long)params[2]:0L
if(attr==sSTLVL && duration>0){ // setLevel takes seconds duration argument (optional)
List larg=[arg, duration.toInteger()]
executePhysicalCommand(rtD,device,attr,larg, delay)
}else executePhysicalCommand(rtD,device,attr,arg, delay)

thx

your second change is incorrect, and I suggest you don't do that. I'll fix the first issue on display.

Both scenarios are already working.

I admit I only just recently started looking at the webCoRE code so its very possible I'm missing something in the bigger picture. However, I don't see what is incorrect with my short code suggestion above. Can you please help me understand why its incorrect?

BTW, I tested my suggestions before I posted and they are working for me. So I'd really like to understand where is incorrect and why you think I shouldn't do that. :thinking:

I can see that you are re-using 'delay' as a local variable to hold the setLevel duration value when the variable name 'delay' is already being used throughout the code as a global variable to store the Piston Execution Delay value. Those are two different timings. Your code puts the setLevel duration value into the 'delay' variable and then passes that value (I believe incorrectly) as the Piston Execution Delay parameter in the "else executePhysicalCommand" line. So everything else that calls the do_setLevel routine is going to get a 0L value for Piston Execution Delay even if it should be something else. It also drops the Piston Execution Delay value from the 1st executePhysicalCommand with the sSTLVL attribute. My suggested change should fix those two things (as far as I can tell).

Does it work correctly? I'm not sure about that. :thinking: The setLevel duration is working now and thats good. But it looks to me like your code fix is no longer honoring the previous Piston Execution Delay properly. Instead of just telling me mine is incorrect, can you please help me understand with a little more details? I am an experienced programmer but am new to the webCoRE code and I would like to understand it better.

@nh.schottfam
Wondering if you could add this really simple change to WC. :wink:
As my HPM updates always fail due to sync problem I have to check the app code manually to make sure I'm up-to-date.
The WC engine text reads the wrong line of the code so it reports the wrong version.
I'm at 0211 on both so the first HE version is incorrect.

image

I've got a C3 hub with Webcore and seeing this today? I'm one version back with WC but on the current version of Hubitat. What is this system event list telling me?

Feature request: Would it be terribly difficult to return something from a piston activated via HTTP, i.e. in the response body?

Don't care much about the exact format, but having the choice of plain text or a json object would be really great.

Thanks.

The severeLoad event, may or may not be related to the webCoRE load piston list request. The System Events is just a list of events that occurred.

To see what is running you should look at the device or app metrics under 'logs'

I don't think this would be webcore, as there are no changes that cause it to use more cpu.

1 Like

Currently piston execute 'fires the piston' with the arguments, but does not wait for it to finish.

It returns 'Ok' or 'ERROR' depending if it was able to fire the piston.

You could always have the piston call an endpoint as it runs

Optionally you can enable pistons to fire a location event when they complete (this is off by default). (HE console -> Apps -> webcore -> settings -> log piston executions)

This fires a location event as the piston exits an execution. It includes in the data piston Id, piston name, event data that fired it, and the piston state information (this is displayed in the dashboard). Some apps (like Echo Speaks) can use this as a trigger into Echo Speaks

I don't think that would work. I have a dashboard implemented as an HTML file. The dashboard runs on a Fire tablet, running Fully Kiosk Browser. The html file is actually stored in HE's file system; there is no web server, nor any need for one. All functionality is implemented in javascript. It makes ajax calls to HE via the Maker API to initiate actions.

I'd like to have the dashboard make an ajax call to webcore to retrieve some values.

Could be wrong, but I don't think there's any way to create an endpoint in javascript that waits for incoming connections.

It is a major architectural change to have an option to allow the piston to run to completion before returning, and have a mechanism to specify a response body?

For everyone -

pushed an update to webcore to do this to try out a suggested method. There is a new endpoint that allows to query global variables.

This also works for HE hub variables via the @@variable format

where redacted and 163 are filled in appropriately to your environment (you can look at the execute piston URLs in HE console -> select a piston -> Execute to understand how to adjust for your deployment)

If you use HPM, do an HPM repair on webcore, otherwise I changed the webcore main file

The usage:

$ curl http://192.168.86.xxx/apps/api/163/global/@HolidayNextDaysAway?access_token=redacted

{"val":26,"result":"OK","timestamp":1613750680295}
$

or

https://cloud.hubitat.com/api/redacted/apps/163/global/@foo?access_token=redacted

2 Likes

This feature has opened a whole new range of possibilities especially sharing data between different platforms such as Node-RED and even webCoRE running on different platforms.

Awesome.

What I have been doing to display updating custom information on the dashboard is using an attribute template on the dashboard and a virtual device that stores the data from WebCoRE.

Driver for virtual device:

metadata {
   	definition (name: "webCoRE Value", namespace: "Derakkon", author: "Derakkon") {
    		capability "Refresh"
    		attribute "Value","string"
    		command "changeValue"
     	}
}
def changeValue (param) {
	sendEvent("name":"Value", "value":param)
}

@nh.schottfam Feature Request
Is it possible to put a delay option (ms, sec) in a With statement?
I can execute a global var with a list of items in a For/Each and put a wait command in the Do but you can't have a With and a list of items execute slower.
Use case here is that my Blink cameras sometimes miss a command because Blink gets the commands too fast. Also my night routines turn off a lot of lights and sometimes the mesh gets overwhelmed with the number Turn Off's.
There may be other block constructs that might benefit from this iteration delay as well.
EDIT: I haven't tried it but if I put a delay in a With block does it actually iterate through the block for each list item, thus using the wait, or does it just execute the commands on the list all at once?
Cheers.