Flows Builder - a visual designer for the new rules engine

workflow
ui
ruleengineexperim
Tags: #<Tag:0x00007f51e085d390> #<Tag:0x00007f51e085d110> #<Tag:0x00007f51e085cfa8>

(Yannick Schaus) #7

Ugh.
Do you have anything in Paper UI, Configuration > Services > UI > Flows Builder?
Is your “Flows Registry” empty?


(Antares2001) #8

Hello

that looks really great! By the way, did anybody so far do a performance comparison between textual rules and rules created with the help of the graphical rule creator?


(Mattwire) #9

I have the following in UI > Flows Builder:
Current flow id: lounge_downstairs_off_button

Flows JSON:

{
    "0700_House_to_day_mode": {
        "next_node_id": 7,
        "next_connector_id": 12,
        "nodes": [
            {
                "module_type_uid": "timer.TimeOfDayTrigger",
                "name": "",
                "id": 1,
                "x": 315,
                "y": 54,
                "type": "trigger",
                "connectors": [
                    {
                        "id": 1,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1409"
                    }
                ],
                "module_config": {
                    "time": "07:00"
                },
                "$$hashKey": "object:1391"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 2,
                "x": 458,
                "y": 209,
                "type": "action",
                "connectors": [
                    {
                        "id": 2,
                        "type": "topConnector",
                        "$$hashKey": "object:1412"
                    },
                    {
                        "id": 3,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1414"
                    }
                ],
                "module_config": {
                    "itemName": "FF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1392"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 3,
                "x": 118,
                "y": 142,
                "type": "action",
                "connectors": [
                    {
                        "id": 4,
                        "type": "topConnector",
                        "$$hashKey": "object:1417"
                    },
                    {
                        "id": 5,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1419"
                    }
                ],
                "module_config": {
                    "itemName": "upstairs_mode",
                    "command": "Day"
                },
                "$$hashKey": "object:1393"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 4,
                "x": 462,
                "y": 374,
                "type": "action",
                "connectors": [
                    {
                        "id": 6,
                        "type": "topConnector",
                        "$$hashKey": "object:1422"
                    },
                    {
                        "id": 7,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1424"
                    }
                ],
                "module_config": {
                    "itemName": "GF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1394"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 5,
                "x": 128,
                "y": 295,
                "type": "action",
                "connectors": [
                    {
                        "id": 8,
                        "type": "topConnector",
                        "$$hashKey": "object:1427"
                    },
                    {
                        "id": 9,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1429"
                    }
                ],
                "module_config": {
                    "itemName": "MF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1395"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 6,
                "x": 164,
                "y": 473,
                "type": "action",
                "connectors": [
                    {
                        "id": 10,
                        "type": "topConnector",
                        "$$hashKey": "object:1432"
                    },
                    {
                        "id": 11,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1434"
                    }
                ],
                "module_config": {
                    "itemName": "downstairs_occupied",
                    "command": "ON"
                },
                "$$hashKey": "object:1396"
            }
        ],
        "edges": [
            {
                "source": 3,
                "destination": 8,
                "$$hashKey": "object:1384"
            },
            {
                "source": 9,
                "destination": 6,
                "$$hashKey": "object:1385"
            },
            {
                "source": 1,
                "destination": 4,
                "$$hashKey": "object:6427"
            },
            {
                "source": 5,
                "destination": 2,
                "$$hashKey": "object:6430"
            },
            {
                "source": 7,
                "destination": 10,
                "$$hashKey": "object:7901"
            }
        ],
        "name": "When the time is 07:00",
        "description": "Turn all lights off, heating on downstairs",
        "updatedTime": "2017-08-20T18:36:24.128Z"
    },
    "0000_House_to_night_mode": {
        "next_node_id": 7,
        "next_connector_id": 12,
        "nodes": [
            {
                "module_type_uid": "timer.TimeOfDayTrigger",
                "name": "",
                "id": 1,
                "x": 315,
                "y": 54,
                "type": "trigger",
                "connectors": [
                    {
                        "id": 1,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1409"
                    }
                ],
                "module_config": {
                    "time": "07:00"
                },
                "$$hashKey": "object:1391"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 2,
                "x": 458,
                "y": 209,
                "type": "action",
                "connectors": [
                    {
                        "id": 2,
                        "type": "topConnector",
                        "$$hashKey": "object:1412"
                    },
                    {
                        "id": 3,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1414"
                    }
                ],
                "module_config": {
                    "itemName": "FF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1392"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 3,
                "x": 118,
                "y": 142,
                "type": "action",
                "connectors": [
                    {
                        "id": 4,
                        "type": "topConnector",
                        "$$hashKey": "object:1417"
                    },
                    {
                        "id": 5,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1419"
                    }
                ],
                "module_config": {
                    "itemName": "upstairs_mode",
                    "command": "Day"
                },
                "$$hashKey": "object:1393"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 4,
                "x": 462,
                "y": 374,
                "type": "action",
                "connectors": [
                    {
                        "id": 6,
                        "type": "topConnector",
                        "$$hashKey": "object:1422"
                    },
                    {
                        "id": 7,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1424"
                    }
                ],
                "module_config": {
                    "itemName": "GF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1394"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 5,
                "x": 128,
                "y": 295,
                "type": "action",
                "connectors": [
                    {
                        "id": 8,
                        "type": "topConnector",
                        "$$hashKey": "object:1427"
                    },
                    {
                        "id": 9,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1429"
                    }
                ],
                "module_config": {
                    "itemName": "MF_Lights",
                    "command": "OFF"
                },
                "$$hashKey": "object:1395"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 6,
                "x": 164,
                "y": 473,
                "type": "action",
                "connectors": [
                    {
                        "id": 10,
                        "type": "topConnector",
                        "$$hashKey": "object:1432"
                    },
                    {
                        "id": 11,
                        "type": "bottomConnector",
                        "$$hashKey": "object:1434"
                    }
                ],
                "module_config": {
                    "itemName": "downstairs_occupied",
                    "command": "ON"
                },
                "$$hashKey": "object:1396"
            }
        ],
        "edges": [
            {
                "source": 3,
                "destination": 8,
                "$$hashKey": "object:1384"
            },
            {
                "source": 9,
                "destination": 6,
                "$$hashKey": "object:1385"
            },
            {
                "source": 1,
                "destination": 4,
                "$$hashKey": "object:6427"
            },
            {
                "source": 5,
                "destination": 2,
                "$$hashKey": "object:6430"
            },
            {
                "source": 7,
                "destination": 10,
                "$$hashKey": "object:7901"
            }
        ],
        "name": "When the time is 07:00",
        "description": "Turn all lights off, heating on downstairs",
        "updatedTime": "2017-08-20T18:36:24.128Z"
    },
    "lounge_downstairs_off_button": {
        "next_node_id": 3,
        "next_connector_id": 4,
        "nodes": [
            {
                "module_type_uid": "core.ChannelEventTrigger",
                "id": 1,
                "x": 210,
                "y": 97,
                "type": "trigger",
                "connectors": [
                    {
                        "id": 1,
                        "type": "bottomConnector",
                        "$$hashKey": "object:169"
                    }
                ],
                "module_config": {
                    "channelUID": "amazondashbutton:dashbutton:15dd2cfa384:press"
                },
                "$$hashKey": "object:166"
            },
            {
                "module_type_uid": "core.ItemCommandAction",
                "name": "",
                "id": 2,
                "x": 317,
                "y": 283,
                "type": "action",
                "connectors": [
                    {
                        "id": 2,
                        "type": "topConnector",
                        "$$hashKey": "object:208"
                    },
                    {
                        "id": 3,
                        "type": "bottomConnector",
                        "$$hashKey": "object:210"
                    }
                ],
                "module_config": {
                    "itemName": "downstairs_occupied",
                    "command": "OFF"
                },
                "$$hashKey": "object:205"
            }
        ],
        "edges": [
            {
                "source": 1,
                "destination": 2,
                "$$hashKey": "object:214"
            }
        ],
        "name": "lounge_downstairs_off_button",
        "description": "Amazon Dash Button to set downstairs_occupied = OFF",
        "updatedTime": "2017-08-21T21:16:32.940Z"
    }
}

(Yannick Schaus) #10

Looks like this node is missing a name for some reason… ngFlowchart requires one when it parses the flow. Must be a bug. You can either add one (even an empty string will do) or get rid of the entire flow (the parent “lounge_downstairs_off_button”) and change the currentFlow value to another flow id, your choice.
If this doesn’t solve the problem, check for other nodes without names.


(Mattwire) #11

Looks like this node is missing a name for some reason

That fixed it, thankyou. I think it probably is a bug. I think I did something like this to trigger it:

  1. Add flow.
  2. Edit node - add name.
  3. Edit node - remove name (use default computed).
  4. Broken.

(Yannick Schaus) #12

Yes, that’s what I supposed happened. Thanks for betatesting! :wink:


Experimental Next-Gen Rules Engine Documentation 1 of : Introduction
Experimental Next-Gen Rules Engine Documentation 3 of : Your First Rule
Next generation design: A Paper UI replacement proposal
(Yannick Schaus) #13

I fixed it, and also added a sweet new feature :slight_smile:
Thanks to Tern and its CodeMirror addon, when editing JavaScript (ECMAScript actually) the script editor now has very decent intellisense, with embedded documentation, type awareness and even partial definitions for ESH/openHAB types and global objects!

It will also try to infer the script context, that is, the outputs of parent nodes (for instance a “state change” trigger will output oldState and newState) and provide autocompletion and intellisense for these too.

Demo of a potential real-work scenario:

Please try it out and report back problems. Enjoy!

Release here: https://github.com/ghys/flowsbuilder/releases/latest


(Yannick Schaus) #14

Useful resource for scripting rules:
https://www.n-k.de/riding-the-nashorn/#_loading_scripts

I learned it’s perfectly possible to do this in a script:

load('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.1/moment.min.js');

// will update the item's state to 'Last Friday at 2:13 PM'
events.postUpdate('MyItem', moment().subtract(6, 'days').calendar());

Another reason for me to definitely try to move away from Xtext rules :wink:


(Yannick Schaus) #15

And even though XMLHttpRequests are not possible in Nashorn, this worked too:
(found here: https://gist.github.com/billybong/a462152889b6616deb02)

/*####################################################################################################################################
# As Nashorn does not have http capabilities through XMLHttpRequest (DOM API), we have to use regular Java classes instead.
# This sample shows how this can be acheived without depending on any third party libraries. Just a standard Java 8 JDK.
# Make sure to have JAVA_HOME/bin on your PATH for the shebang to work. Then just chmod +x away and run...
# Alternatively if you're on a non *nix OS, start with jjs -scritping httpsample.js
####################################################################################################################################*/

var url = "https://api.github.com/repos/openhab/openhab-distro";
var response;

response = httpGet(url).data;

var repo = JSON.parse(response);

events.postUpdate('Open_Issues', repo.open_issues_count);


/*************
UTILITY FUNCTIONS
*************/

function httpGet(theUrl){
    var con = new java.net.URL(theUrl).openConnection();
    con.requestMethod = "GET";

    return asResponse(con);
}

function httpPost(theUrl, data, contentType){
    contentType = contentType || "application/json";
    var con = new java.net.URL(theUrl).openConnection();

    con.requestMethod = "POST";
    con.setRequestProperty("Content-Type", contentType);

    // Send post request
    con.doOutput=true;
    write(con.outputStream, data);

    return asResponse(con);
}

function asResponse(con){
    var d = read(con.inputStream);

    return {data : d, statusCode : con.responseCode};
}

function write(outputStream, data){
    var wr = new java.io.DataOutputStream(outputStream);
    wr.writeBytes(data);
    wr.flush();
    wr.close();
}

function read(inputStream){
    var inReader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream));
    var inputLine;
    var response = new java.lang.StringBuffer();

    while ((inputLine = inReader.readLine()) != null) {
           response.append(inputLine);
    }
    inReader.close();
    return response.toString();
}

(Yannick Schaus) #16

I added an autocompletion for items in the script editor, just open a string literal ("") where an item name is expected and hit Ctrl+Space:

flowsbuilder-items-autocomplete

and a little debugger for sending commands and monitoring SSE events because why not :smile: :

Also you can copy-paste nodes now, including between flows. Use the regular keyboard shortcuts, Ctrl-X/C/V.

IMPORTANT: Unpublish all rules made with previous releases before trying out 2.2.0.201708251715! This release won’t be able to see them!


(Kuba Wolanin) #17

Dude. This is like the most awesome thing ever! :open_mouth:


(Yannick Schaus) #18

Spent a couple hours on the debugger this morning:

The log messages are more user friendly (not all event types are recognized).

Add items to a watchlist and monitor their states.
You can also send update the state from the watchlist by editing the text box and hitting Return:
this will send a command (or hit Esc to discard your changes).
Add an item to the watchlist by clicking its name in the log.

This might be useful to you even if you don’t use the other features.


(Mattwire) #19

@ysc Really enjoying the debugger!

I see you set “visibility: hidden” for rules in the latest version - but that seems to have the side effect of them not being shown when using the REST API: eg. http://openhab:8080/rest/rules. Do you have any suggestions? Otherwise I’ll raise this as an issue against eclipse smarthome


(Yannick Schaus) #20

@mattwire Thanks!

About the rules being hidden now: this is intentional, to avoid polluting the view in Paper UI with “technical” rules, and discourage editing them directly. Certainly not an issue with ESH!

They are tagged with the ID of the flow so for example if you published rules related to “flow1” they can still be listed with: http://openhab:8080/rest/rules?tags=flow1

If you’re not sure exactly about which rules are in your system you can always check out the JSON DB in userdata/jsondb/automation_rules.json


Event Scheduler - REST API?
(Mattwire) #21

Yes, the problem is there seems to be no way to retrieve all hidden rules from the API without first knowing the rule exists. On the text console you can run automation listRules and that returns everything.


(Mattwire) #22

The reason for doing this is I have an issue with rules not initialising at openhab startup (see New rule engine startup - rule initialisation)


(Yannick Schaus) #23

Ah, good to know. Another possible solution is to leave the “root” rules (those with triggers) visible and hide the “additional” ones (those created when traversing the flow).


(James Hiscott) #24

Up and working. Thank @ysc. Simple rules are now so quick to make. And the debugging alone is awesome!

I could do with having some multi-trigger rules and merging paths, but understand the complication / limitation currently.

I think this will become very popular for new users very quickly.


(James Hiscott) #25

Still using this to make rules i think it will be an awesome addition.

Some things i have noticed:

  1. When you press “Delete” on they keyboard if you are editing some text in the “Module Configuration” section it removes the full node. I was only expecting it to remove the text character i was editing. Note: backspace works fine
  2. you dont seem to be able to copy and paste into the the text boxs in the configuration panel
  3. When you add the “say something” blob it doesnt let you select the Audio sink from a drop down like the “pay a sound” does
  4. it would be nice to be able to see the debug panel while in the configuration panel

Thanks again for the effort so far.


(Yannick Schaus) #26

Thanks for the reports :slight_smile:
1. & 2. are essentially the same silly bug - the event handlers for deleting and copy-pasting nodes take precedence even when the focus is in a text box; I’ll have a fix
3. happens in Paper UI too, there is apparently a mistake in the config descriptions for the “say something” module
4. could be tricky - what’s wrong with simply deselecting the node?