[1.1.0] Using observe to continuously look for pattern and take actions

Asked by Shafiq Khan

Here's the structure of the script:

def MainFunction():
    #1. initialize program
    #2. call a bunch of functions to do various things within a infinite loop

def Disconnected():
    #This function closes disconnect message and attempts to continue from #2 above

def IdleObserver():
    regionDisconnect.onAppear(disconnectPattern, Disconnected)
    observe(FOREVER,background=True)

Goal is to detect any disconnect, call a function (e.g. Disconnected()) to remedy the situation, resume from #2 in MainFunction() and resume observing for disconnects.

Where/how do I call this IdleObserver() function so that when disconnectPattern is detected, it calls Disconnected() and then goes back to observing for disconnectPattern? Is there a better way to accomplish the same goal?

Question information

Language:
English Edit question
Status:
Answered
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
RaiMan (raimund-hocke) said :
#1

-- 1. this only works with version 1.1.0

-- 2. as the parameters say: the observe runs in background completely parallel to the main script. Just call the idleObserver once at the beginning.

-- 3. concurrent mouse and keyboard usage:
up to version 1.0.1 it could happen, that the handler (Disconnected in your case) took over in the middle of a mouse action in the main workflow, which usually led to crashes.
There was no easy way, to avoid such situations.
Now with version 1.1.0 mouse actions like click are "atomical" operations , that are completed, before another thread can do his mouse action. It is even possible to pack a serious of mouse actions into one "transaction", that is completed, before any other thread can use the mouse.
The features are very new and not tested in all aspects, but should work in your situation out of the box with a simple click.

-- 4. how to

once before going into your main flow:
idleObserver()

which starts the observing in background

your handler should have:

def Disconnected(event):
    #This function closes disconnect message using a click
    event.region.click(button) # clicks the button in the observed region
    event.repeat(someSeconds) # waits someSeconds until continuing to observe (someSeconds = 0: continue without waiting)

without the repeat(), the observation would terminate after the first appearance.

in your main loop nothing has to be done: if the handler gets active with it's click, the next mouse action in the main workflow simply waits until the click in the handler is completed and then continues.

Be aware: there are no automatics currently, that prevent your main workflow to crash, if the popup you are waiting for in this moment hides something you are waiting for in the main workflow.
The only means in the moment: raise the waiting time accordingly for the critical sections/finds

One more thing:
Sorry, but this is not yet in the docs.
So come back with more questions.

Revision history for this message
Shafiq Khan (srk8887) said :
#2

If someone went crazy and wanted to stick with 1.0.1 for various reasons, would multithreading be the way to go?

Revision history for this message
RaiMan (raimund-hocke) said :
#3

Not really crazy to stick with 1.0.1, as long as it works and has the features you need.

Of course you can use your own multithreading (observe in background is indeed running in it's own thread at the Java level), but what is missing in 1.0.1 is mouse synchronization. (see comment #1 --3.)

You would have to implement your own mouse usage locking, which surely adds much boiler plate code to your workflow.

Revision history for this message
Shafiq Khan (srk8887) said :
#4

That makes quite a strong case for upgrading to 1.1.0.

If I am trying to observe for multiple patterns, what's the most efficient way? Multiple observers?

Revision history for this message
RaiMan (raimund-hocke) said :
#5

Each background observe is run in it's own thread.

One region can only have one observe active, but can have as many on... events as needed.
The events are checked sequentially one after the other restarting the check earliest after a pause given by the ObserveScanRate.

Generally the search region should be as small as possible.

having more than one observer might give some performance boost on multi-cpu machines (I have no experiences and benchmarks and might depend from the Java version used).

The decision on how many observers one should have is mainly dependent from the need for different handlers.

If you only wait for different popups in some area of the screen, that only need to be clicked away with the same button, then one observe with such a generic handler might be sufficient.

Another aspect is cpu usage: since visual searching (observe is only a special use of it) is mainly number crunching, you have to have an eye on your cpu usage and in doubt use scan rates that reduce the frequency of observe checks.

So you have to find your own way.

Revision history for this message
Shafiq Khan (srk8887) said :
#6

Got it. Can you please elaborate on event.repeat(someSeconds). Usage etc.

Revision history for this message
RaiMan (raimund-hocke) said :
#7

With the implementation of the observe in 1.1.0 I decided to delegate the observe control into the handler.

So an observe principally stops automatically with the first event occurring (where event is one specific on...).
If there are more than one events per observe, only the events that did not happen yet are observed until happening the first time.

This is especially useful for observing in background:
- you decide, wether you want to repeat the observation of the event by using repeat (which otherwise would not be observed any longer)
event.repeat() # simply keeps observing alive for this event after returning from the handler
event.repeat(secs) # does the same, but pauses the observation for this event for the given time in seconds after returning from the handler

This allows to adjust the scan rate for a specific event independently from the overall ObserveScanRate.

There is an additional neat feature:
event.getCount()
tells you how often this event already happened during the running observe in background.
This gives you additional options to control the observe cycle.

Revision history for this message
Shafiq Khan (srk8887) said :
#8

def reactToDisconnect():
    #clicks any 'x' or 'OK' button to close disconnect error popups

def dcObserver():
    region.onAppear(xButton, reactToDisconnect())
    region.onAppear(okButton, reactToDisconnect())
    observe(FOREVER,background=True)

dcObserver()

Is this the right way of observing for multiple patterns? Also, I couldn't implement repeat in there. Where exactly do I implement it. What is the parent class of repeat?

Revision history for this message
RaiMan (raimund-hocke) said :
#9

pls. read again carefully my comment #1
and have a look at
http://sikulix-2014.readthedocs.org/en/latest/region.html#observing-visual-events-in-a-region
for the principal usage of observe and how to define a handler.

Your solution is principally ok, if in the given region the mentioned buttons are only visible in the cases, that you want to handle with the observe.

Revision history for this message
Shafiq Khan (srk8887) said :
#10

Already made the move to 1.1.0. However, can you please give me an example of repeat() outside of pseudo code. Whatever I do, sikuli can't find repeat().

Revision history for this message
RaiMan (raimund-hocke) said :
#11

--- sikuli can't find repeat().
I do not understand what you mean.

from comment #1 and according to the docs about the handler:

def Disconnected(event):
    #This function closes disconnect message using a click
    event.region.click(button) # clicks the button in the observed region
    event.repeat(someSeconds) # waits someSeconds until continuing to observe (someSeconds = 0: continue without waiting)

should work

about the API:
http://nightly.sikuli.de/docs/index.html

the above event parameter is of class ObserveEvent

Revision history for this message
Shafiq Khan (srk8887) said :
#12

Thank you RaiMan. I was actually putting "event.repeat(FOREVER)" and IDE was giving me error. But this cleared things up.

You said there can be only one observer per region. So if I wanted to observe two things in two different regions of the screen more efficiently, would this be the right thing to do:

def reactToDisconnect():
    #clicks any 'x' or 'OK' button to close disconnect error popups

def xButtonObserver():
    regUpperHalf.onAppear(xButton, reactToDisconnect())
    observe(FOREVER,background=True)
    regUpperHalf.repeat()

def okButtonObserver():
    regLowerHalf.onAppear(okButton, reactToDisconnect())
    observe(FOREVER,background=True)
    regUpperHalf.repeat()

xButtonObserver() #Observing for x on upper half of the screen
okButtonObserver() #Observing for OK on lower half of the screen
mainScript()

Or would it be better to enlarge the region to some middle 2/3rd and use only that region twice?

Revision history for this message
RaiMan (raimund-hocke) said :
#13

the answer see comment #5

Revision history for this message
Shafiq Khan (srk8887) said :
#14

Ah. Got it. Thank you again.

Can you help with this problem?

Provide an answer of your own, or ask Shafiq Khan for more information if necessary.

To post a message you must log in.