How to send all EG events over tcp w/o creating a macro??
Posted: Thu Jan 10, 2013 1:10 am
I'm working on a tcp plug-in that will connect to my home automation (HA) server (called SYS or Premise) and allow for two-way communications. My HA server can then trigger actions in EventGhost (such as send OSD messages), send events with payload (to trigger EG macros) , and receive events from EventGhost (to trigger things in the HA server).
Everything works (code is below), but the only way I can get EventGhost events sent to my home automation server is to include the Premise: SendEvent action in a macro along with whatever events I want to receive. This is a manual task of dragging all events that I want into a macro, then adding the "SendEvent" action.
I'd like to have all EventGhost events automatically be sent. I'm hoping there's a way to do this with a plug-in? As implied from above, whatever solution must work over the network via a tcp listener. Please help!
PS: I'm new to EventGhost, so please do not assume I know anything (beyond what the plug-in does below), but I did do a lot of reading so that I could write the plug-in...
Here's the code I have now for SendEvent:
Here's the entire plug-in:
Everything works (code is below), but the only way I can get EventGhost events sent to my home automation server is to include the Premise: SendEvent action in a macro along with whatever events I want to receive. This is a manual task of dragging all events that I want into a macro, then adding the "SendEvent" action.
I'd like to have all EventGhost events automatically be sent. I'm hoping there's a way to do this with a plug-in? As implied from above, whatever solution must work over the network via a tcp listener. Please help!
PS: I'm new to EventGhost, so please do not assume I know anything (beyond what the plug-in does below), but I did do a lot of reading so that I could write the plug-in...
Here's the code I have now for SendEvent:
Code: Select all
# this action will send the string and payload of an EventGhost event to the SYS server.
class SendEvent(eg.ActionClass):
description = "Sends to the connected Premise server the EventGhost event string and payload (as a string) that initiated the action."
def __call__(self):
sEventString = str(eg.event.string)
sEventPayload = str(eg.event.payload)
self.plugin.SendCmd_Event(sEventString, sEventPayload)Code: Select all
eg.RegisterPlugin(
name = "Premise",
author = "etc6849",
version = "1.0",
guid = '{85f83859-9bb5-4112-9be6-04c5ff5e6ce8}',
canMultiLoad = False,
description = "Send and receive events or actions to and from a Premise home automation server. Download Premise for free at http://www.cocoontech.com/wiki/Premise",
)
import eg
import select, time
import asynchat
import xml.dom.minidom as xmldom
from socket import *
from threading import Event, Thread
# define the plugin that will send/receive actions and also send events to a connect SYS server
# note 1: SYS server refers to the Premise home automation server.
# note 2: this plugin is disigned to handle more than one connection.
class Premise(eg.PluginBase):
def __init__(self):
self.AddAction(SetValue)
self.AddAction(SendEvent)
print "Init..."
def __start__(self, host, port):
self.theSock = socket(AF_INET, SOCK_STREAM)
self.host = host
self.port = port
self.data = ''
bound = 0
while bound == 0 :
bound = 1
try :
addr = (self.host, self.port)
self.theSock.bind(addr)
except :
bound = 0
print "Socket error"
self.theSock.listen(5)
print "Premise plugin bound to port " + str(self.port)
self.input = [self.theSock]
self.output = []
self.errored = []
self.mainThreadEvent = Event()
mainThread = Thread(target=self.main, args=(self.mainThreadEvent,))
mainThread.start()
def __stop__(self):
print "Stopping...please wait..."
self.mainThreadEvent.set()
# main loop
def main(self,mainThreadEvent):
self.client = None
while not self.mainThreadEvent.isSet():
inputready,outputready,errored = select.select(self.input,self.output,self.errored,1)
for s in inputready:
if s == self.theSock:
self.client, address = self.theSock.accept()
print "Client added: ", self.client, address
if not self.input.count(self.client)>0:
self.input.append(self.client)
else:
# receive upto 4096 bytes of data
data = s.recv(4096)
tempConn = self.input[1:len(self.input)]
# if data is received do something with it
if data:
# get rid of any line terminators from the packet
data = self.StripNoPrint(data)
print "Processing data: ", data
# process <ACTION> packet received from the SYS server
if '<ACTION>' in data:
self.ProcessCmd_Action(data)
# process <EVENT> packet received from the SYS server
if '<EVENT>' in data:
self.ProcessCmd_Event(data)
# echo back data to each connection
for i in tempConn:
# echo the data back along with a CR
i.send(data + "\r")
# set an event trigger in EventGhost
eg.TriggerEvent(str(s.getpeername()) + ": " + data)
else:
if self.input.count(s) > 0:
self.input.remove(s)
print "Client removed: ", s
self.theSock.close()
print "Main thread has ended"
# define Configure panel
def Configure(self, host = '0.0.0.0', port = 1024):
panel = eg.ConfigPanel(self)
mySizer = wx.GridBagSizer(5, 5)
hostControl = wx.TextCtrl(panel, -1, host)
mySizer.Add(wx.StaticText(panel,-1,"Host ip or blank: "),(2,0))
mySizer.Add(hostControl,(2,1))
portControl = panel.SpinIntCtrl(port, 1024, 1024)
portControl.SetInitialSize((60,-1))
mySizer.Add(wx.StaticText(panel,-1,"Port number: "),(3,0))
mySizer.Add(portControl,(3,1))
panel.sizer.Add(mySizer, 0, flag = wx.EXPAND)
while panel.Affirmed():
panel.SetResult(hostControl.GetValue(),portControl.GetValue())
def StripNoPrint(self, str):
results = ""
# iterate through and remove all non-printable ascii characters
for char in str:
if ord(char) > 31 and ord(char) < 127:
results += char
return results
def ProcessCmd_Action(self, sCommand):
# replace the first occurance of the tag with nothing
sCommand = sCommand.replace("<ACTION>", "", 1)
print "Processing action: " + sCommand
# this will invoke an action based on received python code from the SYS server
eg.plugins.EventGhost.PythonCommand(sCommand)
return ''
def ProcessCmd_Event(self, sCommand):
# replace the first occurance of the tag with nothing
sCommand = sCommand.replace("<EVENT>", "", 1)
# remove all "<" from array
sCommand = sCommand.replace("<", "")
# split the packet into a list
sCommand = sCommand.split(">")
# trigger event in EG, process payload if it's present
if sCommand[1] == "":
print "Processing event: " + sCommand[0]
self.TriggerEvent(sCommand[0])
else:
print "Processing event and payload: " + sCommand[0] + "\'" + sCommand[1] + "\'"
self.TriggerEvent(sCommand[0], payload = sCommand[1])
return ''
# send the event string and event payload (as a string) to the SYS server
def SendCmd_Event(self, sEventString, sEventPaload):
sCommand = "<EVENT>" + "<" + sEventString + "><" + sEventPaload + ">"
# send EVENT packet to all connected SYS servers
tempConn = self.input[1:len(self.input)]
for i in tempConn:
i.send(sCommand + "\r")
print "Sending event: " + sCommand
return ''
# send a setvalue request to the SYS server in order to change some object's property
def SendCmd_SetValue(self, sObjPath, sPropName, sPropValue, bForceStateChange):
sCommand = "<SETVAL>"
if bForceStateChange:
sCommand = "<SETVALFORCE>"
sCommand = sCommand + "<" + sObjPath + "><" + sPropName + "><" + sPropValue + ">"
# send SetValue packet to all connected SYS servers
tempConn = self.input[1:len(self.input)]
for i in tempConn:
i.send(sCommand + "\r")
print "Sending setvalue: " + sCommand
return ''
# this action will invoke the SetValue and SetValueForce methods within SYS using the passed parameters.
class SetValue(eg.ActionClass):
description = "Calls the SetValue method on the connected Premise server using the supplied parameters."
def __call__(self, sObjPath, sPropName, sPropValue, bForceStateChange):
self.plugin.SendCmd_SetValue(sObjPath, sPropName, sPropValue, bForceStateChange)
# build the configuration panel
def Configure(self, sObjPath="Home.Living.Light", sPropName="PowerState", sPropValue="True", bForceStateChange=0 ):
panel = eg.ConfigPanel()
sObjPathControl = panel.TextCtrl(sObjPath)
sPropNameControl = panel.TextCtrl(sPropName)
sPropValueControl = panel.TextCtrl(sPropValue)
bForceStateChangeControl = panel.CheckBox(bForceStateChange)
panel.AddLine("Use options below to define the desired Premise server action. Values are not case sensitive.")
panel.AddLine("SYS Object Path: ", sObjPathControl)
panel.AddLine("Property Name: ", sPropNameControl)
panel.AddLine("Property Value: ", sPropValueControl)
panel.AddLine("Force State Change: ", bForceStateChangeControl)
while panel.Affirmed():
panel.SetResult(sObjPathControl.GetValue(),sPropNameControl.GetValue(),sPropValueControl.GetValue(), bForceStateChangeControl.GetValue())
# this action will send the string and payload of an EventGhost event to the SYS server.
class SendEvent(eg.ActionClass):
description = "Sends to the connected Premise server the EventGhost event string and payload (as a string) that initiated the action."
def __call__(self):
sEventString = str(eg.event.string)
sEventPayload = str(eg.event.payload)
self.plugin.SendCmd_Event(sEventString, sEventPayload)