Trying to get the best approach

If you have a question or need help, this is the place to be.
Post Reply
cobraman44
Posts: 12
Joined: Mon Oct 09, 2017 6:27 pm

Trying to get the best approach

Post by cobraman44 » Mon Oct 09, 2017 6:58 pm

I have been searching through the forum for days now.. but still not sure what approach to take.
My thought is to have a master python script that figures out what I sent to it ( this for the Amazon Echo integration)
Then based on what I decide, call another macro/script. Get the results returned then send a reply.
I have not been able to figure this out. How to call another macro/script from a python script and return results.
Should I be looking at this from another angle? I could put everything in one large script but I really did not want to do that.
I have everything else working within one script.. Say a command and it returns what I want.

FYI. My test example that works in a single script
I say: Alexa ask chuck if the garage door is open
alexa responds: Chuck says the door is wide open.

I am a just getting my feet wet with EventGhost and I can think of a LOT of uses once I get this going and manageable.
Thanks

User avatar
kgschlosser
Site Admin
Posts: 3115
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Trying to get the best approach

Post by kgschlosser » Tue Oct 10, 2017 12:24 am

When I get home I will key up an example for you. It's rather difficult to code from a cell phone. But because of how EG works it's going to be semi complicated.

I need s better understand of how you want everything laid out. You want to basically call a script from inside of another script and have it return some data. Do you need to see things being logged? Because you can simply set up a script and in that script you will encapsulate your code to be run into a function. def SomeFunction() this will make a code block callable so you can run it at any point in your script. Now. Just because it is made in a script doesn't make it accessable from another. That is why there is eg.globals. this is a container for things that can be globally accessed. From anywhere inside of EG. We use it by placing the next line right after your function. eg.globals.SomeFunction = SomeFunction. You would add the Main.OnInit event to the macro that has this python script. This will assign the global right when EG starts. So in your script that you want to be able to access it you would use eg.globals.SomeFunction(). The other way is by using a combination of events/payloads and threading. If you want the latter let me know.
If you like the work I have been doing then feel free to Image

cobraman44
Posts: 12
Joined: Mon Oct 09, 2017 6:27 pm

Re: Trying to get the best approach

Post by cobraman44 » Tue Oct 10, 2017 2:24 pm

kgschlosser wrote:
Tue Oct 10, 2017 12:24 am
When I get home I will key up an example for you. It's rather difficult to code from a cell phone. But because of how EG works it's going to be semi complicated.

I need s better understand of how you want everything laid out. You want to basically call a script from inside of another script and have it return some data. Do you need to see things being logged? Because you can simply set up a script and in that script you will encapsulate your code to be run into a function. def SomeFunction() this will make a code block callable so you can run it at any point in your script. Now. Just because it is made in a script doesn't make it accessable from another. That is why there is eg.globals. this is a container for things that can be globally accessed. From anywhere inside of EG. We use it by placing the next line right after your function. eg.globals.SomeFunction = SomeFunction. You would add the Main.OnInit event to the macro that has this python script. This will assign the global right when EG starts. So in your script that you want to be able to access it you would use eg.globals.SomeFunction(). The other way is by using a combination of events/payloads and threading. If you want the latter let me know.
Thanks for the explanation. The latter sounds like what I am talking about. I want to think of other Macros/Scripts as functions that I want to call from the main script with data returning. My goal is to create a template macro that can just be copied and a couple of changes made to be used. As you mentioned I can do this all in one script but seems like that may get a little out of control, but that is why I was looking for some advice. These different macros/scripts could be doing a lot of different things (query HA, computer controls, IFTTT, etc). Base on the voice commands from alexa or maybe other triggers (schedules, network broadcast) I could use the same macro/script. Let me know if I am way off base on this. Again thanks for the help

cobraman44
Posts: 12
Joined: Mon Oct 09, 2017 6:27 pm

Re: Trying to get the best approach

Post by cobraman44 » Tue Oct 10, 2017 10:14 pm

kgschlosser wrote:
Tue Oct 10, 2017 12:24 am
When I get home I will key up an example for you. It's rather difficult to code from a cell phone. But because of how EG works it's going to be semi complicated.

I need s better understand of how you want everything laid out. You want to basically call a script from inside of another script and have it return some data. Do you need to see things being logged? Because you can simply set up a script and in that script you will encapsulate your code to be run into a function. def SomeFunction() this will make a code block callable so you can run it at any point in your script. Now. Just because it is made in a script doesn't make it accessable from another. That is why there is eg.globals. this is a container for things that can be globally accessed. From anywhere inside of EG. We use it by placing the next line right after your function. eg.globals.SomeFunction = SomeFunction. You would add the Main.OnInit event to the macro that has this python script. This will assign the global right when EG starts. So in your script that you want to be able to access it you would use eg.globals.SomeFunction(). The other way is by using a combination of events/payloads and threading. If you want the latter let me know.
I had replied to this once and it has not shown up. Cannot remember what all I wrote. But I think what I wanted was the latter. I would like to call Macros/Script from another and return results like a function. That way I can call them from other Macros/scripts the same way

cobraman44
Posts: 12
Joined: Mon Oct 09, 2017 6:27 pm

Re: Trying to get the best approach

Post by cobraman44 » Thu Oct 12, 2017 6:10 pm

So I have figured out how to pass variables to another macro. Using eventtrigger and payload. It processes all this just fine. I just need to figure a way to pass back to the calling script. Is there something like myvariable = eg.TriggerEvent(eventid, prefix="Alexa", payload=["check", "status"])
Or would it be better as suggested above to create a bunch of global functions instead of Macros. The global functions should return data to the calling script in macro right?

yokel22
Experienced User
Posts: 153
Joined: Thu Feb 05, 2015 5:56 pm
Location: U.S. - Kansas city

Re: Trying to get the best approach

Post by yokel22 » Thu Oct 12, 2017 7:01 pm

Your not going to be able to get returned data to the script with a triggerEvent action. You'll need to set it up as a function that returns data.

Setup a script like this. You'll need to initialize the script each time EG restarts. You can do this by running the script on the 'MainOnInit' event, or by putting it in your tree's autostart.

Code: Select all

def myFunction():
    eg.plugins.EventGhost.ShowOSD(u'My function was called!!!', u'0;-24;0;0;0;700;0;0;0;1;0;0;2;32;Arial', (255, 255, 255), (0, 0, 0), 4, (0, 0), 0, 3.0, None)
    return 'test return data'
    
eg.globals.testFunction = myFunction
then from your other scripts call it like this.

Code: Select all

runFunction = eg.globals.testFunction()
print runFunction

User avatar
kgschlosser
Site Admin
Posts: 3115
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Trying to get the best approach

Post by kgschlosser » Thu Oct 12, 2017 11:19 pm

*** EDITED to fix an error in the code. Originally I used event.shouldEnd.wait and this was an incorrect usage.

just set the data to be returned to eg.result. or an eg.global.

But You can also get data returned from an event if you wanted to. simply make sure you send a payload that is a mutable object like a dict a list or class instance. and you would spawn a thread to trigger the event and continue running the script. eg.TriggerEvent returns eg.event and there is a threading.Event object we can use to hold the thread up until the event finishes running.

Code: Select all


import threading

def run():
    payload = dict()
    event = eg.TriggerEvent('some_event', payload=payload)
    t_event = Threading.Event()
    
    # This is going to loop endlessly until the Event has ended. the wait 
    # simply gives the thread something to do.
    while not event.isEnded:
        t_event.wait(0.1)
    
    # make sure in the other script you add whatever it is that needs 
    # to get returned into eg.event.payload when you do this the data
    # will "appear" in the payload here then do whatever it is you want 
    # to do with the data. once you are done using the data unless it 
    # has to be used elsewhere make sure you delete it. the reason why
    # is because what I have recently found out is that a script will hold
    # the variable name and any data in it until the next time the script 
    # runs. So we do not want anything kicking around that might cause 
    # what I call phantoms in your programming.
    del payload

t = threading.Thread(target=run)
t.daemon = True
t.start()
now if you want to forego the use of threads to accomplish this

Code: Select all


def callback(data):
    # same as before use the data and then delete it
    del data


event = eg.TriggerEvent('some_event', payload=dict())
event.AddUpFunc(callback, event.payload)

If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 3115
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Trying to get the best approach

Post by kgschlosser » Thu Oct 12, 2017 11:27 pm

There really is no one right solution. it all depends on your preference of how to do it.

Personally I would rather not set a bunch of functions into the globals and have to keep track of what script set what and where and why and did it get set so another script can use it. that's a way that could be a big pain to try and debug. I personally like either of the 2 solutions I provided. They both technically speaking do use different threads. but the latter will cause the action thread to stop and process your callback. by doing this it causes any events that come into the system to be places into a queue until your callback is done processing what it needs to. the first one will do it's thing not holding anything up.
If you like the work I have been doing then feel free to Image

cobraman44
Posts: 12
Joined: Mon Oct 09, 2017 6:27 pm

Re: Trying to get the best approach

Post by cobraman44 » Sat Oct 14, 2017 12:37 pm

Thanks so much. I just used the non threading way you provided and it works perfectly. That is just what I was looking for.

User avatar
kgschlosser
Site Admin
Posts: 3115
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Trying to get the best approach

Post by kgschlosser » Sat Oct 14, 2017 2:09 pm

I had an error in the threading one. I have corrected it and posted a note about the error. My I was looking at the event handling last night and noticed my error.

Sorry it took me a while to respond with some suggestions for a solution. I had to think about the different ways to go about it. and what would be the easiest to implement. But I am glad you were able to use one of the solutions.
If you like the work I have been doing then feel free to Image

User avatar
kgschlosser
Site Admin
Posts: 3115
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Trying to get the best approach

Post by kgschlosser » Sat Oct 14, 2017 2:38 pm

There is another solution to this as well. that does not involve a callback or threading.

Code: Select all


payload = dict()
event = eg.EventGhostEvent(prefix='Some', suffix='Event', payload=payload)
event.Execute()
# access your payload variable for any of the data that has been changed.
# remember to delete the payload as you do now want those phantom problems
del payload

the reason why we can do this is because the script that is running is running in the action thread already. by creating the event directly we are able to bypass it being added to the action threads queue. so the event will not have to wait to get triggered it gets done immediately.
If you like the work I have been doing then feel free to Image

Post Reply