livebox:hah_plugboard_v2

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
livebox:hah_plugboard_v2 [2012/03/18 18:45] brettlivebox:hah_plugboard_v2 [2015/01/20 00:37] (current) – [BSC] Explain input/output direction values. brett
Line 8: Line 8:
  
 Consider the following use cases: Consider the following use cases:
-  * Send a twitter message when the power being monitored with currentcost goes above 2kW+  * Send a twitter message when the power being monitored with Current Cost goes above 2kW
   * If the temperature drops below 10C turn on a heater turning it off again when it reaches 12C   * If the temperature drops below 10C turn on a heater turning it off again when it reaches 12C
-  * When a currentcost/temperature event is seen, log it to pachube+  * When a Current Cost/temperature event is seen, log it to pachube
   * If Input 1 goes high turn on Relay 1   * If Input 1 goes high turn on Relay 1
   * If RF 1 is turned on schedule a Google calendar event to turn it off in 1 hour   * If RF 1 is turned on schedule a Google calendar event to turn it off in 1 hour
-  * Log a calendar event whenever Input 2 changes state+  * Log a Google calendar event whenever Input 2 changes state
   * If no change is detected on Input 3 during the last 2 hours, send an SMS message   * If no change is detected on Input 3 during the last 2 hours, send an SMS message
-  * If a change is detected on Input 4 AND a named calendar event is still active, send an email+  * If a change is detected on Input 4 AND a named Google calendar event is still active, send an email
   * If 'uptime' is > a given number of hours, perform a scheduled reboot   * If 'uptime' is > a given number of hours, perform a scheduled reboot
  
-It's possible to cascade rules in the plug-board. It's also possible to code circular dependency which the script-er must be careful to avoid.+It's possible to cascade rules in the plug-board. It's also possible to code circular dependency which the scripter must be careful to avoid.
  
-In this model we want to decouple the producers from the consumers and use a scripting intermediary, the plug-board, to perform an action.  With N producers and N consumers we have N*N ways of plugging these together making a very flexible and expandable system.  Consumers can also be thought of as SERVICE providers as they accept an xAP message and perform something useful.+In this model we want to decouple the producers from the consumers and use a scripting intermediary, the plugboard, to perform an action.  With N producers and N consumers we have N*N ways of plugging these together making a very flexible and expandable system.  Consumers can also be thought of as SERVICE providers as they accept an xAP message and perform something useful.
  
 Example of how the script engine is used to interpret a tweet command to turn on a relay. Example of how the script engine is used to interpret a tweet command to turn on a relay.
Line 29: Line 29:
   * This message is picked up by the xap-twitter components and broadcast as an xAP alias command   * This message is picked up by the xap-twitter components and broadcast as an xAP alias command
   * The script engine interprets this alias and re-transmits a 'RELAY on' command   * The script engine interprets this alias and re-transmits a 'RELAY on' command
-  * 'Relay on' is seen by the adapter and is processed as a control for the HAH hardware+  * 'Relay on' is seen by the adapter and is processed as a control for the HAH hardware, thus turning the relay on
  
 Examples of daemons that currently conform to this model are: Examples of daemons that currently conform to this model are:
Line 36: Line 36:
     * CONSUMER: for sending a tweet.     * CONSUMER: for sending a tweet.
   * xap-googlecal   * xap-googlecal
-    * PRODUCER: monitors google calendar and pushes whatever command has been registered. +    * PRODUCER: monitors Google calendar and pushes whatever command has been registered. 
-    * CONSUMER: used as a service to create calendar events.+    * CONSUMER: used as a service to create Google calendar events.
   * xap-sms   * xap-sms
     * PRODUCER: emits an xAP message when an SMS is received     * PRODUCER: emits an xAP message when an SMS is received
Line 70: Line 70:
  
 ===== Basics ===== ===== Basics =====
 +The first thing to note is that using the plugboard generally takes a little personal effort. There are sample scripts available to help get you going, but it is assumed that you can prepare a script, get it onto the HAH and run it. Being familiar with tools such as FTP & vi, together with a basic knowledge of some Unix commands will make your work with the plugboard a lot easier. Familiarity of how [[http://www.xapautomation.org/index.php?title=Getting_started|xAP]] works will help too. The extension library has been designed to do much of the 'hard work' for you. Best of all, once you get the basic knowledge under your belt, there is a whole world of possibility for rule based processing and actioning.
  
 There are only two calls that are needed to build an xAP Lua application. There are only two calls that are needed to build an xAP Lua application.
  
 ^^ **Return Type** ^^ **Method** ^^ **Description** ^^ ^^ **Return Type** ^^ **Method** ^^ **Description** ^^
-|| void|| xap.init(source,uid) || Initialize an xAP application, bind with a hub if found and send a heartbeat every minute ||+|| void|| xap.init(source,uid)\\ **deprecated** || Initialise an xAP application, bind with a hub if found and send a heartbeat every minute\\ __source__ - a fully qualified 'vendorid.deviceid.instance' address. || 
 +|| void|| xap.init{vendorid=,deviceid=,instance=,uid=}\\ || Initialize an xAP application, bind with a hub if found and send a heartbeat every minute.\\ __vendorid__ - optional, default 'dbzoo'\\ __deviceid__ - optional, default to hostname or setting from /etc/xap.d/system.ini\\ __instance__ - mandatory, last component of 'vendorid.deviceid.instance' xAP address specification.\\ __uid__ - mandatory, a unique identifier ||
 || void|| xap.process() || Enter the xAP processing loop || || void|| xap.process() || Enter the xAP processing loop ||
 || void|| xap.send(msg) || Send RAW data on the well known xAP UDP port 3639 || || void|| xap.send(msg) || Send RAW data on the well known xAP UDP port 3639 ||
 || String || xap.expandShortMsg(msg) || Inject/Replace xap-header information in a message || || String || xap.expandShortMsg(msg) || Inject/Replace xap-header information in a message ||
 || void|| xap.sendShort(msg) || A shortcut for send(expandShortMsg(msg)) || || void|| xap.sendShort(msg) || A shortcut for send(expandShortMsg(msg)) ||
 +|| String || xap.buildXapAdddress{vendorid=,deviceid=,instance=} || Build an xAP address target string. vendorid and deviceid will default following the same rules as xap.init{} ||
 +|| String || xap.getDeviceID() || Returns the resolved deviceid, either hostname or /etc/xap.d/system.ini override ||
  
 In its most simplistic form a basic application would look like this; It wouldn't do much except send a heartbeat every minute but it's functional. In its most simplistic form a basic application would look like this; It wouldn't do much except send a heartbeat every minute but it's functional.
Line 84: Line 88:
 <code lua> <code lua>
 require("xap") require("xap")
-xap.init("dbzoo.lua.simple","FF00DD00")+xap.init{instance="simple",uid="FF00DD00"}
 xap.process() xap.process()
 </code> </code>
  
 When building plugboard applets these calls won't need to be made as the plugboard engine will take care of it.  They will be needed if writing standalone Lua applications something you'll do whilst in development/testing mode.  More on writing Applets later. When building plugboard applets these calls won't need to be made as the plugboard engine will take care of it.  They will be needed if writing standalone Lua applications something you'll do whilst in development/testing mode.  More on writing Applets later.
- 
 ===== Frame ===== ===== Frame =====
  
Line 126: Line 129:
 print(f) -- Implicitly calls the tostring() method as above. print(f) -- Implicitly calls the tostring() method as above.
  
--- These assertion are all TRUE, that is the message is *not* displayed.+-- These assertions are all TRUE, that is the message is *not* displayed.
  
 assert(f:getType() == xap.MSG_ORDINARY, "getType failure") assert(f:getType() == xap.MSG_ORDINARY, "getType failure")
Line 164: Line 167:
 ^^ **Return Type** ^^ **Method** ^^ **Description** ^^ ^^ **Return Type** ^^ **Method** ^^ **Description** ^^
 || Filter || xap.Filter(filter) || Constructor || || Filter || xap.Filter(filter) || Constructor ||
 +|| void || <obj>:destroy() || Destructor ||
 || void || <obj>:add(section,key,value) || A condition matching an inbound xAP message, as many filters as needed can be added to the Filter object for matching. || || void || <obj>:add(section,key,value) || A condition matching an inbound xAP message, as many filters as needed can be added to the Filter object for matching. ||
 +|| void || <obj>:delete(section,key,value) || Removing a matching condition from a filter ||
 || void || <obj>:callback(function, userdata) || When all the filter conditions are met invoke the function, the function has a single parameter this is the FRAME matched by the filters.  The function passed will receive as parameters (frame, userdata) || || void || <obj>:callback(function, userdata) || When all the filter conditions are met invoke the function, the function has a single parameter this is the FRAME matched by the filters.  The function passed will receive as parameters (frame, userdata) ||
  
Line 184: Line 189:
 </note> </note>
  
-The constructor can also accept a set of filter patterns directly these are equivalent. +The constructor can also accept a set of filter patterns directlythese are equivalent. 
-<code>+<code lua>
   filter = xap.Filter()   filter = xap.Filter()
   filter:add("xap-header","class","xapbsc.event")   filter:add("xap-header","class","xapbsc.event")
Line 226: Line 231:
 end end
  
-xap.init("dbzoo.lua.test","FF00CC00")+xap.init{instance="test",uid="FF00CC00"}
 f = xap.Filter() f = xap.Filter()
 f:add("xap-hbeat","source",xap.FILTER_ANY) f:add("xap-hbeat","source",xap.FILTER_ANY)
Line 253: Line 258:
  
 <code lua> <code lua>
 +require "xap"
 elapsed = 0 elapsed = 0
  
-function tick(self)+function tick(self, userdata)
   elapsed = elapsed + self.interval   elapsed = elapsed + self.interval
   print("Tick "..elapsed)   print("Tick "..elapsed)
   if elapsed > 10 then   if elapsed > 10 then
-    print(self.userdata)+    print(userdata)
     self:stop()     self:stop()
   end     end  
Line 265: Line 271:
  
 xap.Timer(tick, 2, "user data!"):start() xap.Timer(tick, 2, "user data!"):start()
 +xap.process()
 </code> </code>
  
 ===== Select ===== ===== Select =====
  
-The select object allows a program to monitor multiple file descriptors, waiting until one of more of the file descriptors become "ready" for some class of I/O operation (eg input possible).  A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g. read) without blocking.+The select object allows a program to monitor multiple file descriptors, waiting until one of more of the file descriptors become "ready" for some class of I/O operation (e.g. input possible).  A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g. read) without blocking.
  
 ^^ **Return Type** ^^ **Method** ^^ **Description** ^^ ^^ **Return Type** ^^ **Method** ^^ **Description** ^^
Line 277: Line 284:
 **Sample usage** **Sample usage**
  
-As this is complex class, although simple enough to use, the sample will be a little larger then normal to show fully how this works.  The code is split into two pieces; the server and the client.+As this is complex class, although simple enough to use, the sample will be a little larger then normal to show fully how this works. The code is split into two pieces; the server and the client.
 The assert() wrapper just makes sure that the call worked ... if not, the code stops at that point. The assert() wrapper just makes sure that the call worked ... if not, the code stops at that point.
  
Line 317: Line 324:
 end end
  
-xap.init("dbzoo.lua.socket","FF00CC00","br0")+xap.init{instance="socket",uid="FF00CC00"}
  
 print("Binding to host '" ..host.. "' and port " ..port.. "...") print("Binding to host '" ..host.. "' and port " ..port.. "...")
Line 360: Line 367:
 ===== BSC ===== ===== BSC =====
  
-This class allows the easy construction of BSC endpoints.  By default the following functionality is provided+This class allows the easy construction of [[http://www.xapautomation.org/index.php?title=Basic_Status_and_Control_Schema|BSC endpoints]].  By default the following functionality is provided:
   * responding to a xAPBSC.query with an xAPBSC.info message   * responding to a xAPBSC.query with an xAPBSC.info message
   * sending a xAPBSC.info message every 2 mins   * sending a xAPBSC.info message every 2 mins
Line 367: Line 374:
 ^^ **Return Type** ^^ **Method** ^^ **Description** ^^ ^^ **Return Type** ^^ **Method** ^^ **Description** ^^
 || Endpoint || Endpoint(table) || Constructor: a container to hold endpoints || || Endpoint || Endpoint(table) || Constructor: a container to hold endpoints ||
 +|| nil || <obj>:destroy() || Destructor: remove the endpoint from existence ||
 || nil || <obj>:sendEvent() || Send xAPBSC.event for this endpoint || || nil || <obj>:sendEvent() || Send xAPBSC.event for this endpoint ||
 || nil || <obj>:sendInfo() || Send xAPBSC.info for this endpoint || || nil || <obj>:sendInfo() || Send xAPBSC.info for this endpoint ||
 || nil || <obj>:setText(string) || Populate the "text=" field and mark the "state=on" || || nil || <obj>:setText(string) || Populate the "text=" field and mark the "state=on" ||
 || nil || <obj>:setDisplayText(string) || Populate the "displaytext=" field and mark the "state=on" || || nil || <obj>:setDisplayText(string) || Populate the "displaytext=" field and mark the "state=on" ||
-|| nil || <obj>:setState(arg) || Populate the "state=" field.  arg is bsc state constant || +|| nil || <obj>:setState(arg) || Populate the "state=" field.  arg is a BSC state constant || 
-|| state || decodeState(string) || helper function to decode a string into a bsc STATE constant, the following string are correctly handled: 1,0,on,off,yes,no,true,false,toggle ||+|| state || decodeState(string) || helper function to decode a string into a BSC state constant, the following strings are correctly handled: 1,0,on,off,yes,no,true,false,toggle ||
  
-The following constants can be used when dealing with the state.+The following constants can be used when dealing with the state:
   * bsc.STATE_ON   * bsc.STATE_ON
   * bsc.STATE_OFF   * bsc.STATE_OFF
   * bsc.STATE_TOGGLE   * bsc.STATE_TOGGLE
  
-More about the Endpoint(table) constructor.  The key for the table may be one of the following+More about the Endpoint(table) constructor.  The key for the table may be one of the following:
  
-**name**: The unique, within the xAP source address, identifier for the endpoint.+**name** : Append the endpoint name. Completes the triple; vendorid.deviceid.instance(:name)
  
-**direction**: Has two possible values bsc.INPUT and bsc.OUTPUT+**instance**: xAP address for the endpoint.  Completes the triple; vendorid.deviceid.(instance) 
 + 
 +**direction**: Has two possible values bsc.INPUT and bsc.OUTPUT.  An OUTPUT endpoint will respond to xAPBSC.cmd events, INPUTS will not.
  
 **type**: BSC supports 3 endpoint types: bsc.STREAM, bsc.LEVEL and bsc.BINARY **type**: BSC supports 3 endpoint types: bsc.STREAM, bsc.LEVEL and bsc.BINARY
Line 404: Line 414:
  
 **displaytext** An additional parameter that may be include in an EVENT of INFO message, configurable with a infoEventCB callback function. **displaytext** An additional parameter that may be include in an EVENT of INFO message, configurable with a infoEventCB callback function.
- 
-**source** The fully qualified target endpoint name. Such as dbzoo.livebox.plugboard:relay.1 
  
 **uid** UID key.  If nothing is provide one will be automatically assigned based on the order of BSC endpoints created so far. **uid** UID key.  If nothing is provide one will be automatically assigned based on the order of BSC endpoints created so far.
Line 427: Line 435:
 end end
  
-xap.init("dbzoo.livebox.test","FF0CC000")+xap.init{instance="test",uid="FF0CC000"}
  
 +-- Form 1 : Constructed using the xAP address from xap.init()
 +-- creates -> dbzoo.livebox.test:lcd, dbzoo.livebox.test:relay.1 etc..
 bsc.Endpoint{name="lcd", direction=bsc.OUTPUT, type=bsc.STREAM, cmdCB=lcdCmd} bsc.Endpoint{name="lcd", direction=bsc.OUTPUT, type=bsc.STREAM, cmdCB=lcdCmd}
 bsc.Endpoint{name="relay.1", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd, infoEventCB=relayInfoEvent} bsc.Endpoint{name="relay.1", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd, infoEventCB=relayInfoEvent}
 bsc.Endpoint{name="relay.2", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd} bsc.Endpoint{name="relay.2", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd}
 +
 +-- Form 2 : vendorid and deviceid default, remaining from instance is appended
 +-- creates -> dbzoo.livebox.my:relay.3
 +bsc.Endpoint{instance="my:relay.3", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd}
 +
 +-- Form 3 : vendorid defaults, override deviceid.
 +-- creates -> dbzoo.test.my:relay.4
 +bsc.Endpoint{deviceid="test", instance="my:relay.4", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd}
 +
 +-- Form 4 : full override all keys
 +-- creates -> hello.test.my:relay.4
 +bsc.Endpoint{vendorid="hello", deviceid="test", instance="my:relay.4", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd}
 +
 +-- Form 5 : Shorter way of doing form 4.
 +-- creates -> helloworld.test.my:relay.5
 +bsc.Endpoint{source="hithere.test.my:relay.5", direction=bsc.OUTPUT, type=bsc.BINARY, cmdCB=relayCmd}
  
 xap.process() xap.process()
Line 459: Line 485:
  
 function init() function init()
-  local e = bsc.Endpoint{source="dbzoo.livebox.Plugboard:gc", direction=bsc.INPUT, type=bsc.STREAM}+  -- Creates:  dbzoo.livebox.Plugboard:gc 
 +  local e = bsc.Endpoint{name="gc", direction=bsc.INPUT, type=bsc.STREAM}
   xap.Timer(update, 60, e):start()   xap.Timer(update, 60, e):start()
 end end
Line 472: Line 499:
   * bsc.sendText(target,text, state)  -- state is optional, defaults to 'on'   * bsc.sendText(target,text, state)  -- state is optional, defaults to 'on'
   * bsc.sendLevel(target, level, state) -- state is optional, defaults to 'on'   * bsc.sendLevel(target, level, state) -- state is optional, defaults to 'on'
-  * bsc.send{} -- takes table of elements. target will always go into the xap-header, all others will be placed into the body of output.state.1+  * bsc.send{} -- takes table of elements. Target will always go into the xap-header, all others will be placed into the body of output.state.1
  
-Its a RAW low level control function that is utilized by the higher level functions:  sendText, sendState, sendLevel+It'a RAW low level control function that is utilized by the higher level functions:  sendText, sendState, sendLevel
  
 STATE can be any of the following: on, off, true, false, 1, 0, toggle (Nominally you would use on and off) STATE can be any of the following: on, off, true, false, 1, 0, toggle (Nominally you would use on and off)
Line 503: Line 530:
 require("xap.bsc") require("xap.bsc")
  
-xap.init("dbzoo.livebox.test","FF00AA00")+xap.init{instance="test",uid="FF00AA00"}
  
 bsc.sendState("dbzoo.livebox.Controller:relay.1", "on") bsc.sendState("dbzoo.livebox.Controller:relay.1", "on")
Line 530: Line 557:
 </code> </code>
  
-The **init()** function will be invoked when the applet it loaded by the plugboard.lua script.+The **init()** function will be invoked when the applet is loaded by the plugboard.lua script.
  
-To be automatically loaded they must be placed in the /etc/plugboard directory and have the suffix Applet.lua.  Example file names:+**To be automatically loaded they must be placed in the /etc/plugboard directory and have the suffix Applet.lua.**  Example file names:
   * hbeatWatchdogApplet.lua   * hbeatWatchdogApplet.lua
   * bindRelaysApplet.lua   * bindRelaysApplet.lua
Line 556: Line 583:
 end end
  
-xap.init("dbzoo.lua.example","FF00DD00")+xap.init{instance="example",uid="FF00DD00"}
 init() init()
 xap.process() xap.process()
Line 570: Line 597:
 ====== More samples ====== ====== More samples ======
  
-Whilst there is flash space some samples will be included with the firmware+Whilst there is flash space available, some samples will be included with the firmware
 <code> <code>
 cd /etc_ro_fs/plugboard/samples cd /etc_ro_fs/plugboard/samples
  • livebox/hah_plugboard_v2.1332096303.txt.gz
  • Last modified: 2012/03/18 18:45
  • by brett