Plugin API: Events from XTension

XTension will call specific functions in your scripts to alert you to new data being available or to send you updated unit information or in response to a script or a user asking you to change the state or value of a unit. Several events are called during the startup sequence to let you load your info, give you access to all the configuration of the units assigned to you and then to let you know that communications have been established and you can now use the XTSendData verb to send info to the device.

The file contains constants necessary for talking to XTension as well as helper functions that setup some of the unit information and other structures that cannot yet be passed directly to your functions due to API limitations.

Check Dependencies

The first call into your script will be to a function defined as “XTCheckDependencies”. This function should make sure that all other python dependencies or other things necessary for your code to function are available and were loaded. If everything looks good you should return True to let XTension know that it can continue. If you cannot run for whatever reason you should issue XTWriteLog commands to describe to the user why you can’t run and then return False. The loading will be stopped and the interface will be quit until it can try again. At it’s most simple you can simply return True from the call by default if there are no other checks that need to be done.

def XTCheckDependencies():
   return True

Debug Mode

If your interface is in debug mode then you should do whatever extra logging is necessary to help a user report enough information to you about a problem. XTension will set a global variable called “xtDebugMode” to a boolean true or false to let you know about the settings in XTension. You can check that global variable at any time, but you can also receive this debugModeChanged event when debug mode is turned on or off. This is optional but can be useful to issue some longer report on data or statistics immediately when debug mode is turned on. For example with the Wifi Thermostat I keep a count of the number of refused requests but never log that info as it’s not usually important, it happens once in a while. But when debug mode is turned on I report that and the number of refused connections for all the other types of requests. Having that info immediately upon turning on debug mode is very useful as it can help to figure out if it’s a problem with a responding device, or that the device isn’t responding at all.

The function takes a single parameter and it will be a boolean telling you what the new value of debug mode is.

def XTDebugModeChanged( newValue):
   XTWriteLog( "the debug value is available available using the debugMode module variable")
   XTWriteLog( "but you can also get an event when the mode has changed in case you wish to log")
   XTWriteLog( "the current state at that time")

New Units

Received whenever there is a new unit, or a unit has had it’s configuration saved in the Edit Unit dialog. Also sent during startup so that you can load up any info you need from the units configuration or your dynamic configuration of the units.

In API version 1 the function receives a single parameter which will be a Tuple list of all the unique ID’s of all units assigned to your interface. You can use those as keys into the XTUnitsById global, or just ignore the passed list as you can walk those lists anytime and they are kept updated by XTension for you.

Once you receive this event you know that the unit information dictionaries stored in the global dictionaries at XTUnitsById and XTUnitsByAddress have been updated to reflect the new information. Each unit will have a dictionary stored in those globals keyed by either their uniqueID string, or a concatenation of their tag and their address. You can access them at any time and get all the keyed data about the unit from XTEnsion as well as the keyed data from your dynamic unit interface, if any, will be added to the dictionary as well. The keys for your interface will correspond to those you defined in the info.json for the interface.

def XTNewUnits( myUnitList):
	writeLog( “There are " + str( len( myUnitList)) + “ units assigned to this interface.")
	print( myUnitList)
	writeLog( "XTUnitsById also has " + str( len( XTUnitsById)) + “ units in it, indexed by the uniqueID string”)

NOTE: that this event will fire when the database is saved in XTension, whenever a unit is edited and it’s configuration saved and also during the initial enabling of the interface. This dictionary will contain things like the value of the unit, but this structure is not updated with every change to the unit so you shouldn’t use this to get data like last activity or value or state. All other configuration is available in it however.

At any time the 2 dictionaries of units can be accessed via the globals like:

  myUnitInfo = xtUnitsById[ theUnitID]
  # or by concatenating the tag and the address
  myUnitInfo = xtUnitsByAddress[ “unitTag” + “12345”]

Configuration Changed

This event is sent to the plugin upon startup and whenever the Interface level information is changed. This will contain all the configuration information from the Edit Interface sheet window as well as all the keys in any dynamic interface you have defined for that info. At this moment that data is not set to a global variable or available via a command so you should save off a copy of the passed dictionary into a global so you can refer to it in other places.

The function should accept a single parameter which will be a python dictionary containing all the keyed values about the interface and your dynamic controls.

In the example below I have a dynamic popup with a key of “pwm1” the selection of that popup is available to me from the passed dictionary and I am printing it out to see if it’s set to what I think it is for debugging.

def XTConfigurationChanged( newConfigInfo):
   global myConfig
   myConfig = newConfigInfo
   writeLog( "pwm1 selected tag: " + myConfig[ 'pwm1'])

Port Opened

When your communications channel is ready this event will be fired. If you have selected “None” as the communications option then this will be called immediately after all the units are registered and the configuration events sent. This lets you know that you may begin to receive data available events and that you can now use the port via the XTSendData command.

def XTPortOpened():
	writeLog( "the script has been alerted to the fact that there is a connection")
	writeLog( "there are " + str( len( XTUnitsById)) + " units associated with this interface")
	writeLog( "starting ping timer")
# since we’re connected, we can begin to ping our device to make sure it’s responding
	global pingTimer 
	pingTimer = XTMakeTimer( xtTimerModeMultiple, 10000, "pingTimerCallback", 0)
def pingTimerCallback( theTag):
	# if we get called here after having not received a response to the last ping then we
	# should quit and restart
	global pingOutstanding
	if pingOutstanding == True:
		XTWriteLog( "no ping received from the device, attempt to reconnect", xtColorRed)
		pingOutstanding = False
		pingOutstanding = True
		XTSendData( "PING\r")


Called when your interface has been disabled and the script host helper app is about to be quit. Perform any shutdown or cleanup actions that you need to here. You can still send data to your connected device as that channel has not been closed yet and there is a short delay after this happens when the ports can still send data.

def shutdown():
	writeLog( "the script has been alerted to the fact that the interface is being quit")
	# if you created the ping timer as in the example for PortOpened then you can stop it here
	# try to make the ping timer clean up and stop
	global pingTimer
	pingTimer = {}

Data Available

This function will be called whenever there is data ready to be read from the pipe or port. If you have set a boundry string in the info.json file then you will get a single call to this for each parsed command. If you have not then any buffering or parsing of the incoming data stream will be up to your script. Do not count on the timing that would make each packet come out as a single event, or that a single event won’t hold only a portion of the complete packet that was sent.

def XTDataAvailable( theData):

	global xtDebugMode
	if xtDebugMode:
		writeLog( “Data Received (" + theData + ")”)

Unit Command

A user or a script in XTension has generate a command that you need to act upon and send the appropriate message to your physical devices or other entities. The command is passed to the function as a Python Dictionary. All commands received will have a xtKeyCommand key in them. What other keys are available depend on the command received. Many commands can both be received here and also sent to XTension. See the documentation of the expected keys and command types in the previous article on Talking To XTension for the full range of options that might be received here.

def XTUnitCommand( theCommand):
   thisCommand = theCommand[ xtKeyCommand]

   if thisCommand == xtCommandOn:
     thisAddress = theCommand[ xtKeyAddress]
     thisTag = theCommand[ xtKeyTag]
     if xtKeyRate in theCommand:
        XTSendData( “ramprate=“ + theCommand[ xtKeyRate] + “\r”)
     XTSendData( thisAddress + “=ON\r”)
   elif thisCommand == xtCommandOff:
     thisAddress = theCommand[ xtKeyAddress]
     thisTag = theCommand[ xtKeyTag]
     XTSendData( thisAddress + “=OFF\r”)

PREVIOUS Plugin API: Talking To XTension NEXT Keyed Data Constants

06_events.txt · Last modified: 2017/06/09 14:34 by James Sentman
CC Attribution-No Derivative Works 3.0 Unported Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0