Ensure value of {flow_name} is correct

Post your feature requets for new triggers, conditions, actions and other improvements.

Moderator: Martin

Locked
clive.pottinger
Posts: 21
Joined: 16 May 2014 13:18

Ensure value of {flow_name} is correct

Post by clive.pottinger » 10 Oct 2017 13:04

The issue:
While executing flowA, the value of {flow_name} is "flowA".
Now flowA performs "Execute Flows: flowB" with "Wait for called flows to finish" and "Return variables to the calling flow".
While flowB is running, the value of {flow_name} is "flowB".
When flowB ends and control is returned to flowA, the value of {flow_name} is still "flowB". This means that whenever the flowA tries to report the name of the flow, it obtains the wrong value.

An example of where this is a problem is logging: I have a set of eval() statements that I use to log information about flow execution and calling depths, but they keep reporting the wrong flow names after one flow executes another. Storing the current {flow_name} in another variable at the start of each flow will not work because the same eval()s are used by all the flows, so each flow would just overwrite the new variable too.

Possible solutions:
1) The value of {flow_name} should be reset after "Execute Flows" completes.
2) There should be an additional option for "Execute Flows" to not return the {flow_name} from the called flow.
3) There should be another function or variable that always contains the name of the current flow.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Ensure value of {flow_name} is correct

Post by Desmanto » 10 Oct 2017 16:16

Don't know if this is by design or bug, and I don't know how your flow works. For meanwhile, you can try to store the value in global list. Create the glovar first : global_flowname, type is list. Then use this script to log the flow name.
addElement(global_flowname);
When the next execution of flow, it will add the current flow name to GloVar list.

When return to the caller flow, use
flowname = global_flowname[length(global_flowname)-2];
to access the flowname prior calling the flow. It will access the second last flow name added to it, which supposed to be the caller flow name.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

clive.pottinger
Posts: 21
Joined: 16 May 2014 13:18

Re: Ensure value of {flow_name} is correct

Post by clive.pottinger » 10 Oct 2017 18:32

Desmanto wrote:For meanwhile, you can try to store the value in global list.
Thanks for the suggestion, Desmanto, however, it will not work for me. In my case I can have several independent flows running simultaneously, so no flow can be sure that the entry at the end of the list refers to it, or that the penultimate entry is the caller - other flows may have added/subtracted from the list.

e.g.
flowA starts - glist = ["flowA"]
flowC starts - glist = ["flowA", "flowC"]
flowA calls flowB
flowB starts - glist = ["flowA", "flowC", "flowB"]
flowB removes the last entry in the list before ending - glist = ["flowA", "flowC"]
flowA retrieves its id by looking at the end of the list and gets "flowC" (which is wrong)
flowA removes the last entry in the list before ending - glist = ["flowA"]
flowC retrieves its id by looking at the end of the list and gets "flowA" (which is wrong)

I could make your idea work, or improve my own idea, if there was some way to get a GUID or PIN for a flow. That would be even better than using the flow's name: I could prefix or suffix the GUID or PIN to certain variable names. So, even if the same flow were running simultaneously 5 times, I would be able to use the GUID or PIN to ensure that each flow uses the variables that were set by that flow and not ones set by a called flow or another instance of the same flow.

e.g.
flowA:
a) Script: {pin}MyName = {flow_name};
b) Execute Flow: flowB
c) Message Dialog: message = "showing info from {{pin}MyName}"

flowB:
d) Script: {pin}MyName = {flow_name};

Since the pins would be different, lines a) and d) would create different variables (e.g. 1576MyName = "flowA" and 67842MyName="flowB").
When control returns to flowA it would display "showing info from flowA" - but again, this would only work if flowA's value for {pin} is not overwritten by the flowB.

It would also mean that two or more copies of flowA could run simultaneously and not interfere with each other.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Ensure value of {flow_name} is correct

Post by Desmanto » 11 Oct 2017 02:48

I still can't get the big picture of your calling flow. Have to brute force the solution here.

If you want to use GUID for each flow, why don't just hardcoded the name directly? in message dialog, just use the flowname directly without variable. or if variable is still needed, create a unique variable for each flow to store the static value of the flow name.
static_flowA = "FlowA";
never write anymore to this value and only read the value.

if the flow_name is needed, then assign the flow_name to this static variable each time it finished executing another flow.
flow_name = static_flowA;
(change the flowA according to the flow)

{pin}MyName seems like you're trying to create dynamic variable. You can check in my index on how to create and refer to it. Beside dynamic variable, you can also create dynamic map, by using the variable as the key to the newMap.

Another method is to check the trigger (assume you trigger it on event). Everytime flowA call flowB, flowB will inherit the trigger from flowA. This variable doesn't change even if you return the value. So before returning the value to flowA (at the end of flow B), use script to check if trigger is equal to triggerA. If true, set the flow_name to "FlowA". You need to create a map of value to check for the trigger, in order to map them to the corresponding flow name.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

clive.pottinger
Posts: 21
Joined: 16 May 2014 13:18

Re: Ensure value of {flow_name} is correct

Post by clive.pottinger » 16 Oct 2017 18:26

Thanks again, Desmanto. I appreciate that it can be hard to resolve or understand an issue when all you have are some text messages.

I have resolved my problem for logging by reworking my scripts. Perhaps if I show you the working version, you might understand what I was trying to get at.

I perform my logging using a set of standardized actions. The first one, Set up logging values initializes the variables that I use and is typically executed when Automagic is first started:

Code: Select all

  <action type="script">
    <useDefaultName>false</useDefaultName>
    <name>Set up logging values </name>
    <script>global_LogIndent = "  ";

global_LogFlowStart='logVar=reverse(sort(findAll(join(getVariableNames(), ","), "logVar_\\\\d+"), true, true));if(length(logVar)==0){logCaller=trigger+" trigger";}else{logCaller=getValue(logVar[0], null)[0];};logPos=length(global_LogIndent) - 1;logVar="logVar_{logPos,numberformat,000}";setValue(logVar, newList(flow_name, logPos));global_LogIndent=left(global_LogIndent, logPos)+"<"+substring(global_LogIndent, logPos);logPrefix="{getDate(),dateformat,yyyy.MM.dd HH:mm:ss.SSS}{global_LogIndent}{getValue(logVar,null)[0]} called by {logCaller}";global_LogIndent=replace(global_LogIndent, "<", "|");{logPrefix}';

global_LogFlowMsg='logVar=reverse(sort(findAll(join(getVariableNames(), ","), "logVar_\\\\d+"), true, true))[0];logPos=getValue(logVar, null)[1];logPrefix="{getDate(),dateformat,yyyy.MM.dd HH:mm:ss.SSS}{left(global_LogIndent, logPos)}»{substring(global_LogIndent, logPos+1)}{getValue(logVar, null)[0]}";';

global_LogFlowEnd='logVar=reverse(sort(findAll(join(getVariableNames(), ","), "logVar_\\\\d+"), true, true))[0];logPos=getValue(logVar, null)[1];global_LogIndent="{left(global_LogIndent, logPos)}>{substring(global_LogIndent, logPos+1)}";logPrefix="{getDate(),dateformat,yyyy.MM.dd HH:mm:ss.SSS}{global_LogIndent}{getValue(logVar,null)[0]} ending";global_LogIndent=replace(left(global_LogIndent, length(global_LogIndent) - 1),">","°");while(endsWith(global_LogIndent, "°")){global_LogIndent=left(global_LogIndent, length(global_LogIndent) - 1);};global_LogIndent=global_LogIndent+" ";removeVariable(logVar);{logPrefix};';
</script>
Afterwards, flows typically begin by executing Log flow start and end by executing Log flow end:

Code: Select all

  </action>
  <action type="write_to_file">
    <useDefaultName>false</useDefaultName>
    <name>Log flow start</name>
    <path>{global_primaryDirectory}/{global_deviceName}Log.txt</path>
    <text>{eval(global_LogFlowStart)} 
</text>
    <append>true</append>
  </action>

Code: Select all

  <action type="write_to_file">
    <useDefaultName>false</useDefaultName>
    <name>Log flow end</name>
    <path>{global_primaryDirectory}/{global_deviceName}Log.txt</path>
    <text>{eval(global_LogFlowEnd)}
</text>
    <append>true</append>
  </action>


When a flow needs to log a message, it executes an action like this one:

Code: Select all

  <action type="write_to_file">
    <useDefaultName>false</useDefaultName>
    <name> Log hello world</name>
    <path>{global_primaryDirectory}/{global_deviceName}Log.txt</path>
    <text>{eval(global_LogFlowMsg)} Hello World 
</text>
    <append>true</append>
  </action>

The log file will look something like this:
2017.10.16 11:02:23.726 < Export Flows To Google Drive_ called by Manual trigger
2017.10.16 11:02:23.960 » Export Flows To Google Drive_ Exporting flows for group General to /storage/emulated/0/Automagic
2017.10.16 11:02:24.080 » Export Flows To Google Drive_ Exporting flows for group Tabitha to /storage/emulated/0/Automagic
2017.10.16 11:02:24.209 » Export Flows To Google Drive_ Exporting flows for group Utility to /storage/emulated/0/Automagic
2017.10.16 11:02:24.496 » Export Flows To Google Drive_ Uploading 3 groups to Google Drive
2017.10.16 11:02:25.950 |< MRP Status Check called by Manual trigger
2017.10.16 11:02:26.195 ||< _GetInternet called by MRP Status Check
2017.10.16 11:02:26.416 ||» _GetInternet WiFi connection to NML_Guest is active
2017.10.16 11:02:26.656 ||> _GetInternet ending
2017.10.16 11:02:27.614 |» MRP Status Check MRP error detected: MRP Status information was not pushed to Google Drive
2017.10.16 11:02:27.677 ||< _Present called by MRP Status Check
2017.10.16 11:02:28.177 ||» _Present showing [Monday's MRP process needs attention (11:2): MRP Status information was not pushed to Google Drive], require acknowledgement = [true]
2017.10.16 11:02:31.883 >|| Export Flows To Google Drive_ ending
2017.10.16 11:02:32.194 °|» _Present Text shown: operation result = [ok]
2017.10.16 11:02:32.500 °|> _Present ending
2017.10.16 11:02:32.575 °> MRP Status Check ending
2017.10.16 11:05:13.351 < Flow1 called by Manual trigger
2017.10.16 11:05:13.433 » Flow1 Hello World
2017.10.16 11:05:13.561 > Flow1 ending
where each flow puts a symbol in an assigned column:
< = flow start
| = flow still executing
» = flow is issuing a message
> = flow end
° = flow in this column ended earlier
This example show three flows running: Export Flows To Google Drive_ starts first, then MRP Status Check starts, Export Flows To Google Drive_ finishes, followed by MRP Status Check, and finally, Flow1 starts and ends.
Last edited by clive.pottinger on 19 Oct 2017 18:09, edited 1 time in total.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Ensure value of {flow_name} is correct

Post by Desmanto » 17 Oct 2017 15:30

Are the script above before rework? or after rework?

I see what you did down there :D Basically you are creating a set of custom defined function which you can call just by using eval(variable_which_store _the_custom_function). That's a brilliant way to do it!!!

For example the logFlowStart one, supposed to be consist of 10-11 lines of code, which you need to paste in a script everytime you wanna use it. Now become a single variable, which can be call from single line of script eval().

Two things if I may add to improve readability and efficiency. First, you probably create the whole script and tested it before in the full version (10 lines). Then you compact it to single line of script. But I don't get your script at first, took a while to finally understand it. You can actually defined the whole script per line by single (or double) quoting each line and join them using additional + sign. Something like

Code: Select all

x =
"a = 1 + 2;" +
"b = 3 + 4;" +
"c = 5 + 6;" ;
When you eval(x), it is the same as eval(x) in this form.

Code: Select all

x = "a = 1 + 2; b = 3 + 4; c = 5 + 6;" ;
But it is easier to read when x is spanned accross multiple lines (even though the formatting still gives green color). It is easier to debug then if something wrong.

Second, you can save some spaces for the GloVar, by merging them into single list. So those 3 GloVar can be compacted to

Code: Select all

global_LogFlow = newList(global_LogFlowStart, global_LogFlowMsg, global_LogFlowEnd)
Later, to refer to each of them, just use global_LogFlow[0], global_LogFlow[1], global_LogFlow[2]. You can delete the rest of the 3 GloVar and only need to use this one, which is the combination of the 3.

Of coz, this is just suggestion, you don't need to change anything if everything is working fine. Everyone's scripting style is different afterall.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

clive.pottinger
Posts: 21
Joined: 16 May 2014 13:18

Re: Ensure value of {flow_name} is correct

Post by clive.pottinger » 19 Oct 2017 18:26

Desmanto wrote:Are the script above before rework? or after rework?
These scripts are from after I reworked them. I added the creation of the logVar_### variables so that each flow would have a set of local variables that described how they were called. And the logVar_ variable with the highest number can safely be assumed to hold the information about the current process (this information includes the original value of flow_name and which column in logPrefix should contain the flow's logging symbol).

Of course, it is not fool-proof. If a flow aborts without calling Log flow end, then everything gets mucked up in the logs. For that reason, I keep the log initialization code (Set up logging values) in a separate script that I can execute at anytime to reinitialize the indenting.
Desmanto wrote:I see what you did down there :D Basically you are creating a set of custom defined function which you can call just by using eval(variable_which_store _the_custom_function). That's a brilliant way to do it!!!
Thanks!
Desmanto wrote:You can actually defined the whole script per line by single (or double) quoting each line and join them using additional + sign.
Why didn't I think of that? :roll: I'll do that right away.
Desmanto wrote:Second, you can save some spaces for the GloVar, by merging them into single list.
Another suggestion that I will implement. Thanks again!

clive.pottinger
Posts: 21
Joined: 16 May 2014 13:18

Re: Ensure value of {flow_name} is correct

Post by clive.pottinger » 20 Oct 2017 17:57

Desmanto, now that you see how I am doing the logging, I hope you can better understand the issue I brought up.

In the logging scripts, I have to jump through hoops to get the name of the current flow; using {logVar} and sorting and reversing {logVar_###}. And even that can be broken if a script does not call Log flow end.

Logging is only one example of where this is an issue. I have other scripts that occasionally crash or report incorrect values.

All that is because I cannot rely on the value of {flow_name} to tell me the name of the current flow, and there is no alternative. If there was something that uniquely identified a flow (or better yet - an executing instance of a flow), then it would be far easier to code these kind of scripts.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Ensure value of {flow_name} is correct

Post by Desmanto » 21 Oct 2017 04:14

Martin planned to implement a new trigger to pass only certain variables. This way the flow_name won't be overwritten. It is at another request thread, which originally mean for template. (but somehow stray away until function :D )
viewtopic.php?f=4&t=7004

Meanwhile, your solution will work. Or if you need to identify the flow, it will be the same as my previous idea, using map of trigger - flow name. But every flow must have trigger and it must triggerred using the their specific trigger, not manual or widget click. You can maintain a GloVar map, example

Code: Select all

global_triggerflowname = newMapFromValues(
"Trigger 1", "Flow name 1",
"Trigger 2", "Flow name 2",
"Trigger 3", "Flow Name 3",
"Trigger 4", "Flow Name 3",
"Trigger 5", "Flow Name 3")
When flow 1 is triggered, it will supply variable {trigger} = "Trigger 1", and {flow_name} = "Flow name 1".
Then in the flow 1, you call flow 2; both variables will be passed to flow 2.
At the beginning of flow 2, it change the {flow_name} to "Flow name 2". This is the problem for you, as when the variable pass back to flow 1, the name has changed.
But the {trigger} stay the same, "Trigger 1". We will use this value to identify the caller flow.

So at the beginning of flow 2, you should put Script

Code: Select all

flow_name = global_triggerflowname[trigger]
Since the {trigger} is "Trigger 1", passing it to the map will produce "Flow name 1", which is the original caller flow.
If your flow has multiple triggers, you should define each trigger to identify the same flow. As shown above, where "Flow Name 3" has 3 trigger (Trigger 3, 4 and 5)
This script won't change anything if flow 2 is triggerred by itself. Since passing the value "Trigger 2", will produce "Flow Name 2" as well.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

Locked