<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.mios.com/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.mios.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Micasaverde</id>
		<title>MiOS - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.mios.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Micasaverde"/>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Special:Contributions/Micasaverde"/>
		<updated>2026-04-10T05:56:09Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.19.8</generator>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2017-02-10T16:44:34Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''subcategory_num''': (number) This is a sub category for the device.&lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP address and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. tostring(v2))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return true&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if an attribute is modified, it will not persist between Luup engine restarts. You need to use [[Luup_Lua_extensions#function:_attr_set|luup.attr_set]] instead. Eg:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local ipAddress = '192.168.l.l2'&lt;br /&gt;
&lt;br /&gt;
-- this will not persist between restarts&lt;br /&gt;
luup.devices[lul_device].ip = ipAddress&lt;br /&gt;
&lt;br /&gt;
-- this will persist between restarts&lt;br /&gt;
luup.attr_set('ip', ipAddress, lul_device)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== variable: event_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the notification/event server. On UI5 it can be either ''cms1.mios.com'' or ''cms2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: ra_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the remote access server. Can be either ''fwd1.mios.com'' or ''fwd2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: pk_accesspoint ===&lt;br /&gt;
&lt;br /&gt;
type: number&lt;br /&gt;
&lt;br /&gt;
Contains the serial number of this Vera.&lt;br /&gt;
&lt;br /&gt;
=== variable: hw_key ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the Vera hardware key.&lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, is_ready returns true. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;incoming&amp;gt; block that only processes data if is_ready(lul_device) is true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device. If the invocation could not be made, only ''error'' will be returned with a value of -1. Otherwise, all 4 values are returned. ''error'' is 0 if the UPnP device reported the action was successful. ''arguments'' is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer.&lt;br /&gt;
&lt;br /&gt;
{{Warning|Currently only Z-Wave and Insteon jobs are returned in the ''job'' parameter.}}&lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local resultCode, resultString, job, returnArguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;SetLoadLevelTarget&amp;quot;, {[&amp;quot;newLoadlevelTarget&amp;quot;] = &amp;quot;50&amp;quot;}, 5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP 'service' + 'variable' will be set to the 'value' for this device. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: value (string) and Unix time stamp (number) of when the variable last changed&lt;br /&gt;
&lt;br /&gt;
Returns the value of the UPnP service + variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). If the service+variable or device does not exist, it returns nothing.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[Example usage]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value, tstamp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value .. &amp;quot; last changed (Epoch): &amp;quot; .. tstamp)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
[[Caution - Incorrect usages]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tonumber(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt; also accepts two parameters. However the parameters are incompatible: the Unix timestamp returned by &amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; is being used as a number base in the function &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt;. The number base is limited to a power of 36 or less and the current timestamps are in the range of thousands of millions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tostring(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tostring&amp;lt;/code&amp;gt; only expects one&lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.  Like attr_get, if the device is zero it sets the top-level user_data json tag.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: string or none  (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If the number 0 is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code logs nil if theDeviceNumber is invalid.&lt;br /&gt;
local theName = luup.attr_get ('name', theDeviceNumber)&lt;br /&gt;
luup.log(theName)&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code fails if theDeviceNumber is invalid.&lt;br /&gt;
luup.log(luup.attr_get ('name', theDeviceNumber))&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: ip_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the IP address for a device.  This is better than setting the &amp;quot;ip&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: mac_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the mac address for a device.  This is better than setting the &amp;quot;mac&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: reload ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Reloads the Luup engine.&lt;br /&gt;
&lt;br /&gt;
=== function: create_device ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* '''device_type''' (string) : This is the device type and should be set to an empty string, so it will be retrieved from the UPnP device file.&lt;br /&gt;
* '''internal_id''' (string) : This is the device '''altid'''.&lt;br /&gt;
* '''description''' (string) : This is the device name.&lt;br /&gt;
* '''upnp_file''' (string) : This is the UPnP device file.&lt;br /&gt;
* '''upnp_impl''' (string) : This is the implementation file.&lt;br /&gt;
* '''ip''' (string)&lt;br /&gt;
* '''mac''' (string)&lt;br /&gt;
* '''hidden''' (boolean)&lt;br /&gt;
* '''invisible''' (boolean)&lt;br /&gt;
* '''parent''' (number) : The device ID of the parent device. Set it to '0' if this device shouldn't have any parents.&lt;br /&gt;
* '''room''' (number) : The room ID. If set to '0', the device won't be put in any room.&lt;br /&gt;
* '''pluginnum''' (number) : Which plugin to install after the device is created. Set it to '0' if no plugin should be installed.&lt;br /&gt;
* '''statevariables''' (string) : Variables and attributes you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use '&amp;lt;code&amp;gt;,&amp;lt;/code&amp;gt;' and '&amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt;' to separate service, variable and value, like this: &amp;lt;code&amp;gt;service,variable=value\nservice,variable=value&amp;lt;/code&amp;gt;&lt;br /&gt;
To set an attribute, leave &amp;quot;service&amp;quot; empty, like this: &amp;lt;code&amp;gt;,variable=value&amp;lt;/code&amp;gt;&lt;br /&gt;
Example: &amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50\n,manufacturer=MiOS&amp;quot;&amp;lt;/source&amp;gt;&lt;br /&gt;
* '''pnpid''' (number) : If this is a device from KitDevice.json, this is the ''PK_KitDevice'' number. Otherwise set this to '0'.&lt;br /&gt;
* '''nochildsync''' (string) : If set to &amp;quot;1&amp;quot;, ignore this device when syncing child devices. Unless you know what you're doing, set it to an empty string.&lt;br /&gt;
* '''aeskey''' (string) : This should be set to an empty string.&lt;br /&gt;
* '''reload''' (boolean) : If ''true'', the Luup engine will be restarted after the device is created.&lt;br /&gt;
* '''nodupid''' (boolean) : Set this to ''false''.&lt;br /&gt;
&lt;br /&gt;
returns: the device ID&lt;br /&gt;
&lt;br /&gt;
{{Warning|All parameters are mandatory.}}&lt;br /&gt;
{{Important|&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; '''MUST''' be either an '''empty string''', or '''the same''' as the one in the device file, otherwise the Luup engine will restart continuously.}}&amp;lt;br&amp;gt;&lt;br /&gt;
This creates the device with the parameters given, and returns the device ID.&lt;br /&gt;
Example: &amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.create_device(&amp;quot;&amp;quot;, &amp;quot;testdevice&amp;quot;, &amp;quot;Test Device&amp;quot;, &amp;quot;D_BinaryLight1.xml&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, false, false, 0, 0, 0, &amp;quot;,manufacturer=MiOS&amp;quot;, 0, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, true, false)&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: device_message ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Available in releases after Feb 2017&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
This adds a system message that is attached to a device and appears in the UI under the device.&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* '''device_id''' (number) : This is the device id number&lt;br /&gt;
* '''status''' (int) : This is the status of message, and corresponds to the job status, and generally determines what color the message appears:&lt;br /&gt;
			job_None=-1,		 ///&amp;lt; no icon&lt;br /&gt;
			job_WaitingToStart=0,///&amp;lt; gray icon&lt;br /&gt;
			job_InProgress=1,  	 ///&amp;lt; blue icon&lt;br /&gt;
			job_Error=2,  		 ///&amp;lt; red icon&lt;br /&gt;
			job_Aborted=3,  	 ///&amp;lt; red icon&lt;br /&gt;
			job_Done=4,  		 ///&amp;lt; green icon&lt;br /&gt;
			job_WaitingForCallback=5, ///&amp;lt; blue icon - Special case used in certain derived classes&lt;br /&gt;
			job_Requeue=6, 		 ///&amp;lt; If the job was aborted and needs to be started, use this special value so we know to clear the m_bQuit flag before starting it&lt;br /&gt;
			job_InProgressPendingData=7 // See note 2011-02-24 in ZWJob_SendData.cpp ::Run&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''message''' (string) : This is the text that appears in the message.&lt;br /&gt;
* '''timeout''' (int) : This is the number of seconds to display the message.  Pass 0 to display it indefinitely&lt;br /&gt;
* '''source''' (string) : This is the source module of the message.  It can be anything, and is generally informational.  It is recommended to use the name of the luup plugin.&lt;br /&gt;
&lt;br /&gt;
return: nothing&lt;br /&gt;
&lt;br /&gt;
{{Warning|All parameters are mandatory.}}&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string and content_type it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the Smartphone Web Interface plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    local lul_content_type = &amp;quot;text/html&amp;quot;&lt;br /&gt;
    return lul_html, lul_content_type&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above.&lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
=== function: job_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever a job is created, finished, or changes state then ''function_name'' will be called.  If the device is nil or not specified, ''function_name'' will be called for all jobs, otherwise only for jobs that involve the specified device.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;)&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;,6)&lt;br /&gt;
&lt;br /&gt;
The first one registers a callback for all devices, the second one only for device 6.  Note that multiple registrations will result in multiple callbacks, so two calls like that means that &amp;quot;mycallback&amp;quot; would be called once for all devices except 6, and for 6 it would be called twice.&lt;br /&gt;
&lt;br /&gt;
The callback function will be passed a table which contains:&lt;br /&gt;
&lt;br /&gt;
device_num: the number of the device&lt;br /&gt;
&lt;br /&gt;
status: the job status, 0-7 as follows&lt;br /&gt;
&lt;br /&gt;
  WaitingToStart=0&lt;br /&gt;
  InProgress=1&lt;br /&gt;
  Error=2&lt;br /&gt;
  Aborted=3&lt;br /&gt;
  Done=4&lt;br /&gt;
  WaitingForCallback=5&lt;br /&gt;
  Requeue=6&lt;br /&gt;
  InProgressPendingData=7&lt;br /&gt;
&lt;br /&gt;
name: the name of the job&lt;br /&gt;
&lt;br /&gt;
type: the C++ class name for the type of job&lt;br /&gt;
&lt;br /&gt;
notes: any notes or progress that set for the job&lt;br /&gt;
&lt;br /&gt;
Here is an example of the callback:&lt;br /&gt;
&lt;br /&gt;
  function mycallback(lul_job)&lt;br /&gt;
    luup.log(&amp;quot;mycallback device #&amp;quot; .. lul_job.device_num .. &amp;quot; status &amp;quot; .. lul_job.status .. &amp;quot; name &amp;quot; .. lul_job.name .. &amp;quot; type &amp;quot; .. lul_job.type .. &amp;quot; notes &amp;quot; .. lul_job.notes);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
and here is the output in LuaUPnP.log from the above function when it is registered to watch a ZWave device which was turned ON:&lt;br /&gt;
&lt;br /&gt;
  50      07/09/14 17:43:43.491   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E998D0&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.492   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.493   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.520   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.543   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.544   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.545   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.576   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.631   luup_log:3: mycallback device #6 status 4 name ON node 2 type ZWJob_SendData notes Transmit was ok &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service ID (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (int), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to 1 if the device is failing, 0 if it's working, and 2 if the device is reachable but there's an authentication error. If device is a string it is interpreted as a udn, if it's a number, as a device id. The lu_status URL will show for the device: &amp;lt;tooltip display=&amp;quot;1&amp;quot; tag2=&amp;quot;Lua Failure&amp;quot;/&amp;gt; and Lua Failure is shown in red in UI5 for the device.&lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if it's past sunset and before sunrise, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with os.time to see how long it will be for the next event.  luup.sunset-os.time is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
required firmware: 1.5.353&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns: operationStatusCode (Number), content (String), httpStatusCode (Number)&lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 3 variables: the first is a numeric error code which is 0 if successful. The second variable is a string containing the contents of the page. The third variable is the HTTP status code. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
* ptr (binary object)&lt;br /&gt;
* id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* device_filename (string)&lt;br /&gt;
* implementation_filename (string)&lt;br /&gt;
* parameters (string)&lt;br /&gt;
* embedded (boolean)&lt;br /&gt;
* [invisible (boolean)] optional&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to device.&lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the &amp;lt;tt&amp;gt;uup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a description which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as ''urn:schemas-upnp-org:device:BinaryLight:1''.&lt;br /&gt;
{{Important|On UI7, the &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; '''MUST''' be either the '''empty string''', or '''the same''' as the one in the device file, otherwise the Luup engine will restart continuously.}}&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the XML file with the UPnP device specification. If the &amp;lt;tt&amp;gt;device_file&amp;lt;/tt&amp;gt; contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;deviceType&amp;lt;/tt&amp;gt; from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually ''('''NOTE''': This applies only for UI5 and older UIs.)''.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the ''embedded'' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a, and = to separate service, variable and value, like this: service,variable=value\nservice...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
io.open&amp;lt;br/&amp;gt;&lt;br /&gt;
io.write&amp;lt;br/&amp;gt;&lt;br /&gt;
io.intercept&amp;lt;br/&amp;gt;&lt;br /&gt;
io.read&amp;lt;br/&amp;gt;&lt;br /&gt;
io.is_connected&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ip (string), port (as number or string), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port.&lt;br /&gt;
&lt;br /&gt;
There is no 'function: close'.&lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), [[Luup_Lua_extensions#device:_string_or_number|optional device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean or nil) &lt;br /&gt;
&lt;br /&gt;
The device id defaults to self, if omitted. In Lua a string can contain binary data, so data may be a binary block. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nil if an error occurred.&lt;br /&gt;
&lt;br /&gt;
The written data is modified depending upon the value of the [[Luup_Plugins_ByHand#&amp;lt;protocol&amp;gt;|&amp;lt;protocol&amp;gt; tag]].&lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false. Unplugging the LAN cable associated with the port, will not set the flag to false.&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job.&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
=== device: string or number ===&lt;br /&gt;
*If a number, it is the device ID&lt;br /&gt;
*If a string, it is the UDN for the UPnP device&lt;br /&gt;
Both of these can be found in the User Interface (UI5) under the advanced Tab as &amp;quot;id&amp;quot; and &amp;quot;local_udn&amp;quot; respectively.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,87)&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,&amp;quot;uuid:4d494342-5342-5645-0057-000001c9d682&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Association</id>
		<title>Association</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Association"/>
				<updated>2016-06-14T20:49:18Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''Associations''' ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.7px; line-height: 19.05px;&amp;quot;&amp;gt;Supported Association Groups&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.7px; line-height: 19.05px;&amp;quot;&amp;gt;Vera edge has support for the following associations groups:&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;GROUP ID: 1 - Lifeline&lt;br /&gt;
&lt;br /&gt;
NUMBER OF NODES IN GROUP: 5&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== &amp;lt;span style=&amp;quot;color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12.7px; line-height: 19.05px;&amp;quot;&amp;gt;Creating a Z-Wave Association&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Note: Leave By default Vera should automatically configure devices checked as explained above, and leave each device's Automatically configure set to 'Default Behavior'. If you tell Vera not to configure the device, Vera will leave the device alone and will not set the associations for you.&lt;br /&gt;
&amp;lt;pre&amp;gt;Please note that you'll have to associate the device A with the device B&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;These are also unique for each device according to the manufacturer. Associations are commonly used to tell sensors to turn on lights, and to associate devices. Refer to the manufacturer's users manual that came with the Z-Wave device to learn how they handle associations. Associations are given an ID or group ID. In this case you'll have to create the association only on the sensor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;To add an association, type in the group ID, which is a number, click 'Add Group' and then check off the Z-Wave devices you want to be associated. Vera will attempt to configure the node, and if successful, you'll see the [[Device_Control_Status#Job_icons|green 'configure job' ok icon].&lt;br /&gt;
&lt;br /&gt;
If it's a battery operated device and Vera can't configure it right away, read the comments above about the Configure node right now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;For '''UI7:'''&lt;br /&gt;
&lt;br /&gt;
Click on the '&amp;gt;' button of your device, then go to Device Options&lt;br /&gt;
&lt;br /&gt;
Add group 1 and hit Add group&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;[[File:Aso1.JPG]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;In our case we'll asociate a sensor with Vera.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;[[File:Aso2.JPG]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;When the association is made properly should be displayed the picture below.&lt;br /&gt;
&lt;br /&gt;
'''Note: If you associate a sensor with a switch at '''Set to:'''and '''Currently:'''should be displayed the id of the switch.'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;[[File:Aso3.JPG]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2016-06-14T20:39:11Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.xml in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 03 = start/stop/reload events&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Replace failed node ==&lt;br /&gt;
&lt;br /&gt;
If you have a Z-Wave node that needs to be replaced with another of the same type, and you want the new node to have the same node ID, be sure the old defective node is removed and powered off.  You must not try to connect it and power it up again.  Connect or power on the new node that will replace it.  It must be unpaired and ready to pair.  Go to the 'advanced' section of the device and choose the 'commands' tab and click 'replace failed'.  Then activate pairing on the new node.  Wait a minute and the new node will be included with the same node id as the old one.&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2015-02-11T22:45:37Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''subcategory_num''': (number) This is a sub category for the device.&lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP address and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. tostring(v2))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return true&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== variable: event_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the notification/event server. On UI5 it can be either ''cms1.mios.com'' or ''cms2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: ra_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the remote access server. Can be either ''fwd1.mios.com'' or ''fwd2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: pk_accesspoint ===&lt;br /&gt;
&lt;br /&gt;
type: number&lt;br /&gt;
&lt;br /&gt;
Contains the serial number of this Vera.&lt;br /&gt;
&lt;br /&gt;
=== variable: hw_key ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the Vera hardware key.&lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, is_ready returns true. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;incoming&amp;gt; block that only processes data if is_ready(lul_device) is true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP 'service' + 'variable' will be set to the 'value' for this device. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: value (string) and Unix time stamp (number) of when the variable last changed&lt;br /&gt;
&lt;br /&gt;
Returns the value of the UPnP service + variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). If the service+variable or device does not exist, it returns nothing.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[Example usage]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value, tstamp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value .. &amp;quot; last changed (Epoch): &amp;quot; .. tstamp)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
[[Caution - Incorrect usages]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tonumber(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt; also accepts two parameters. However the parameters are incompatible: the Unix timestamp returned by &amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; is being used as a number base in the function &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt;. The number base is limited to a power of 36 or less and the current timestamps are in the range of thousands of millions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tostring(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tostring&amp;lt;/code&amp;gt; only expects one&lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.  Like attr_get, if the device is zero it sets the top-level user_data json tag.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: string or none  (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If the number 0 is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code logs nil if theDeviceNumber is invalid.&lt;br /&gt;
local theName = luup.attr_get ('name', theDeviceNumber)&lt;br /&gt;
luup.log(theName)&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code fails if theDeviceNumber is invalid.&lt;br /&gt;
luup.log(luup.attr_get ('name', theDeviceNumber))&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: ip_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the IP address for a device.  This is better than setting the &amp;quot;ip&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: mac_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the mac address for a device.  This is better than setting the &amp;quot;mac&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: reload ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Reloads the Luup engine.&lt;br /&gt;
&lt;br /&gt;
=== function: create_device ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* internal_id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* upnp_file (string)&lt;br /&gt;
* upnp_impl (string)&lt;br /&gt;
* ip (string)&lt;br /&gt;
* mac (string)&lt;br /&gt;
* hidden (boolean)&lt;br /&gt;
* invisible (boolean)&lt;br /&gt;
* parent (number)&lt;br /&gt;
* room (number)&lt;br /&gt;
* pluginnum (number)&lt;br /&gt;
* statevariables (string)&lt;br /&gt;
* pnpid (number)&lt;br /&gt;
* nochildsync (string)&lt;br /&gt;
* aeskey (string)&lt;br /&gt;
* reload (boolean)&lt;br /&gt;
* nodupid (boolean)&lt;br /&gt;
&lt;br /&gt;
returns: the device ID&lt;br /&gt;
&lt;br /&gt;
This creates the device with the parameters given, and returns the device ID.&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string and content_type it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the Smartphone Web Interface plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    local lul_content_type = &amp;quot;text/html&amp;quot;&lt;br /&gt;
    return lul_html, lul_content_type&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above.&lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
=== function: job_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever a job is created, finished, or changes state then ''function_name'' will be called.  If the device is nil or not specified, ''function_name'' will be called for all jobs, otherwise only for jobs that involve the specified device.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;)&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;,6)&lt;br /&gt;
&lt;br /&gt;
The first one registers a callback for all devices, the second one only for device 6.  Note that multiple registrations will result in multiple callbacks, so two calls like that means that &amp;quot;mycallback&amp;quot; would be called once for all devices except 6, and for 6 it would be called twice.&lt;br /&gt;
&lt;br /&gt;
The callback function will be passed a table which contains:&lt;br /&gt;
&lt;br /&gt;
device_num: the number of the device&lt;br /&gt;
&lt;br /&gt;
status: the job status, 0-7 as follows&lt;br /&gt;
&lt;br /&gt;
  WaitingToStart=0&lt;br /&gt;
  InProgress=1&lt;br /&gt;
  Error=2&lt;br /&gt;
  Aborted=3&lt;br /&gt;
  Done=4&lt;br /&gt;
  WaitingForCallback=5&lt;br /&gt;
  Requeue=6&lt;br /&gt;
  InProgressPendingData=7&lt;br /&gt;
&lt;br /&gt;
name: the name of the job&lt;br /&gt;
&lt;br /&gt;
type: the C++ class name for the type of job&lt;br /&gt;
&lt;br /&gt;
notes: any notes or progress that set for the job&lt;br /&gt;
&lt;br /&gt;
Here is an example of the callback:&lt;br /&gt;
&lt;br /&gt;
  function mycallback(lul_job)&lt;br /&gt;
    luup.log(&amp;quot;mycallback device #&amp;quot; .. lul_job.device_num .. &amp;quot; status &amp;quot; .. lul_job.status .. &amp;quot; name &amp;quot; .. lul_job.name .. &amp;quot; type &amp;quot; .. lul_job.type .. &amp;quot; notes &amp;quot; .. lul_job.notes);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
and here is the output in LuaUPnP.log from the above function when it is registered to watch a ZWave device which was turned ON:&lt;br /&gt;
&lt;br /&gt;
  50      07/09/14 17:43:43.491   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E998D0&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.492   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.493   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.520   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.543   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.544   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.545   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.576   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.631   luup_log:3: mycallback device #6 status 4 name ON node 2 type ZWJob_SendData notes Transmit was ok &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service ID (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (int), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to 1 if the device is failing, 0 if it's working, and 2 if the device is reachable but there's an authentication error. If device is a string it is interpreted as a udn, if it's a number, as a device id. The lu_status URL will show for the device: &amp;lt;tooltip display=&amp;quot;1&amp;quot; tag2=&amp;quot;Lua Failure&amp;quot;/&amp;gt; and Lua Failure is shown in red in UI5 for the device.&lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if it's past sunset and before sunrise, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with os.time to see how long it will be for the next event.  luup.sunset-os.time is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
required firmware: 1.5.353&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
* ptr (binary object)&lt;br /&gt;
* id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* device_filename (string)&lt;br /&gt;
* implementation_filename (string)&lt;br /&gt;
* parameters (string)&lt;br /&gt;
* embedded (boolean)&lt;br /&gt;
* [invisible (boolean)] optional&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to device.&lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the &amp;lt;tt&amp;gt;uup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a description which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as ''urn:schemas-upnp-org:device:BinaryLight:1''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;'''NOTE:''' On UI7, the &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; '''MUST''' be either the '''empty string''', or '''the same''' as the one in the device file, otherwise the Luup engine will restart continuously.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the XML file with the UPnP device specification. If the &amp;lt;tt&amp;gt;device_file&amp;lt;/tt&amp;gt; contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;deviceType&amp;lt;/tt&amp;gt; from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually ''('''NOTE''': This applies only for UI5 and older UIs.)''.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the ''embedded'' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a, and = to separate service, variable and value, like this: service,variable=value\nservice...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
io.open&amp;lt;br/&amp;gt;&lt;br /&gt;
io.write&amp;lt;br/&amp;gt;&lt;br /&gt;
io.intercept&amp;lt;br/&amp;gt;&lt;br /&gt;
io.read&amp;lt;br/&amp;gt;&lt;br /&gt;
io.is_connected&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ip (string), port (as number or string), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port.&lt;br /&gt;
&lt;br /&gt;
There is no 'function: close'.&lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), [[Luup_Lua_extensions#device:_string_or_number|optional device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean or nil) &lt;br /&gt;
&lt;br /&gt;
The device id defaults to self, if omitted. In Lua a string can contain binary data, so data may be a binary block. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nil if an error occurred.&lt;br /&gt;
&lt;br /&gt;
The written data is modified depending upon the value of the [[Luup_Plugins_ByHand#&amp;lt;protocol&amp;gt;|&amp;lt;protocol&amp;gt; tag]].&lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false. Unplugging the LAN cable associated with the port, will not set the flag to false.&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job.&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
=== device: string or number ===&lt;br /&gt;
*If a number, it is the device ID&lt;br /&gt;
*If a string, it is the UDN for the UPnP device&lt;br /&gt;
Both of these can be found in the User Interface (UI5) under the advanced Tab as &amp;quot;id&amp;quot; and &amp;quot;local_udn&amp;quot; respectively.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,87)&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,&amp;quot;uuid:4d494342-5342-5645-0057-000001c9d682&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2015-02-11T21:48:38Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''subcategory_num''': (number) This is a sub category for the device.&lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP address and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. tostring(v2))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return true&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== variable: event_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the notification/event server. On UI5 it can be either ''cms1.mios.com'' or ''cms2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: ra_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the remote access server. Can be either ''fwd1.mios.com'' or ''fwd2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: pk_accesspoint ===&lt;br /&gt;
&lt;br /&gt;
type: number&lt;br /&gt;
&lt;br /&gt;
Contains the serial number of this Vera.&lt;br /&gt;
&lt;br /&gt;
=== variable: hw_key ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the Vera hardware key.&lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, is_ready returns true. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;incoming&amp;gt; block that only processes data if is_ready(lul_device) is true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP 'service' + 'variable' will be set to the 'value' for this device. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: value (string) and Unix time stamp (number) of when the variable last changed&lt;br /&gt;
&lt;br /&gt;
Returns the value of the UPnP service + variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). If the service+variable or device does not exist, it returns nothing.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[Example usage]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value, tstamp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value .. &amp;quot; last changed (Epoch): &amp;quot; .. tstamp)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
[[Caution - Incorrect usages]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tonumber(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt; also accepts two parameters. However the parameters are incompatible: the Unix timestamp returned by &amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; is being used as a number base in the function &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt;. The number base is limited to a power of 36 or less and the current timestamps are in the range of thousands of millions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tostring(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tostring&amp;lt;/code&amp;gt; only expects one&lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.  Like attr_get, the device is optional and if not specified sets the top-level user_data json tag.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: string or none  (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If nothing is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code logs nil if theDeviceNumber is invalid.&lt;br /&gt;
local theName = luup.attr_get ('name', theDeviceNumber)&lt;br /&gt;
luup.log(theName)&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code fails if theDeviceNumber is invalid.&lt;br /&gt;
luup.log(luup.attr_get ('name', theDeviceNumber))&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: ip_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the IP address for a device.  This is better than setting the &amp;quot;ip&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: mac_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the mac address for a device.  This is better than setting the &amp;quot;mac&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: reload ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Reloads the Luup engine.&lt;br /&gt;
&lt;br /&gt;
=== function: create_device ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* internal_id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* upnp_file (string)&lt;br /&gt;
* upnp_impl (string)&lt;br /&gt;
* ip (string)&lt;br /&gt;
* mac (string)&lt;br /&gt;
* hidden (boolean)&lt;br /&gt;
* invisible (boolean)&lt;br /&gt;
* parent (number)&lt;br /&gt;
* room (number)&lt;br /&gt;
* pluginnum (number)&lt;br /&gt;
* statevariables (string)&lt;br /&gt;
* pnpid (number)&lt;br /&gt;
* nochildsync (string)&lt;br /&gt;
* aeskey (string)&lt;br /&gt;
* reload (boolean)&lt;br /&gt;
* nodupid (boolean)&lt;br /&gt;
&lt;br /&gt;
returns: the device ID&lt;br /&gt;
&lt;br /&gt;
This creates the device with the parameters given, and returns the device ID.&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string and content_type it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the Smartphone Web Interface plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    local lul_content_type = &amp;quot;text/html&amp;quot;&lt;br /&gt;
    return lul_html, lul_content_type&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above.&lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
=== function: job_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever a job is created, finished, or changes state then ''function_name'' will be called.  If the device is nil or not specified, ''function_name'' will be called for all jobs, otherwise only for jobs that involve the specified device.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;)&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;,6)&lt;br /&gt;
&lt;br /&gt;
The first one registers a callback for all devices, the second one only for device 6.  Note that multiple registrations will result in multiple callbacks, so two calls like that means that &amp;quot;mycallback&amp;quot; would be called once for all devices except 6, and for 6 it would be called twice.&lt;br /&gt;
&lt;br /&gt;
The callback function will be passed a table which contains:&lt;br /&gt;
&lt;br /&gt;
device_num: the number of the device&lt;br /&gt;
&lt;br /&gt;
status: the job status, 0-7 as follows&lt;br /&gt;
&lt;br /&gt;
  WaitingToStart=0&lt;br /&gt;
  InProgress=1&lt;br /&gt;
  Error=2&lt;br /&gt;
  Aborted=3&lt;br /&gt;
  Done=4&lt;br /&gt;
  WaitingForCallback=5&lt;br /&gt;
  Requeue=6&lt;br /&gt;
  InProgressPendingData=7&lt;br /&gt;
&lt;br /&gt;
name: the name of the job&lt;br /&gt;
&lt;br /&gt;
type: the C++ class name for the type of job&lt;br /&gt;
&lt;br /&gt;
notes: any notes or progress that set for the job&lt;br /&gt;
&lt;br /&gt;
Here is an example of the callback:&lt;br /&gt;
&lt;br /&gt;
  function mycallback(lul_job)&lt;br /&gt;
    luup.log(&amp;quot;mycallback device #&amp;quot; .. lul_job.device_num .. &amp;quot; status &amp;quot; .. lul_job.status .. &amp;quot; name &amp;quot; .. lul_job.name .. &amp;quot; type &amp;quot; .. lul_job.type .. &amp;quot; notes &amp;quot; .. lul_job.notes);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
and here is the output in LuaUPnP.log from the above function when it is registered to watch a ZWave device which was turned ON:&lt;br /&gt;
&lt;br /&gt;
  50      07/09/14 17:43:43.491   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E998D0&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.492   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.493   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.520   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.543   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.544   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.545   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.576   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.631   luup_log:3: mycallback device #6 status 4 name ON node 2 type ZWJob_SendData notes Transmit was ok &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service ID (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (int), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to 1 if the device is failing, 0 if it's working, and 2 if the device is reachable but there's an authentication error. If device is a string it is interpreted as a udn, if it's a number, as a device id. The lu_status URL will show for the device: &amp;lt;tooltip display=&amp;quot;1&amp;quot; tag2=&amp;quot;Lua Failure&amp;quot;/&amp;gt; and Lua Failure is shown in red in UI5 for the device.&lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if it's past sunset and before sunrise, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with os.time to see how long it will be for the next event.  luup.sunset-os.time is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
required firmware: 1.5.353&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
* ptr (binary object)&lt;br /&gt;
* id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* device_filename (string)&lt;br /&gt;
* implementation_filename (string)&lt;br /&gt;
* parameters (string)&lt;br /&gt;
* embedded (boolean)&lt;br /&gt;
* [invisible (boolean)] optional&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to device.&lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the &amp;lt;tt&amp;gt;uup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a description which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as ''urn:schemas-upnp-org:device:BinaryLight:1''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;'''NOTE:''' On UI7, the &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; '''MUST''' be either the '''empty string''', or '''the same''' as the one in the device file, otherwise the Luup engine will restart continuously.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the XML file with the UPnP device specification. If the &amp;lt;tt&amp;gt;device_file&amp;lt;/tt&amp;gt; contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;deviceType&amp;lt;/tt&amp;gt; from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually ''('''NOTE''': This applies only for UI5 and older UIs.)''.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the ''embedded'' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a, and = to separate service, variable and value, like this: service,variable=value\nservice...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
io.open&amp;lt;br/&amp;gt;&lt;br /&gt;
io.write&amp;lt;br/&amp;gt;&lt;br /&gt;
io.intercept&amp;lt;br/&amp;gt;&lt;br /&gt;
io.read&amp;lt;br/&amp;gt;&lt;br /&gt;
io.is_connected&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ip (string), port (as number or string), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port.&lt;br /&gt;
&lt;br /&gt;
There is no 'function: close'.&lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), [[Luup_Lua_extensions#device:_string_or_number|optional device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean or nil) &lt;br /&gt;
&lt;br /&gt;
The device id defaults to self, if omitted. In Lua a string can contain binary data, so data may be a binary block. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nil if an error occurred.&lt;br /&gt;
&lt;br /&gt;
The written data is modified depending upon the value of the [[Luup_Plugins_ByHand#&amp;lt;protocol&amp;gt;|&amp;lt;protocol&amp;gt; tag]].&lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false. Unplugging the LAN cable associated with the port, will not set the flag to false.&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job.&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
=== device: string or number ===&lt;br /&gt;
*If a number, it is the device ID&lt;br /&gt;
*If a string, it is the UDN for the UPnP device&lt;br /&gt;
Both of these can be found in the User Interface (UI5) under the advanced Tab as &amp;quot;id&amp;quot; and &amp;quot;local_udn&amp;quot; respectively.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,87)&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,&amp;quot;uuid:4d494342-5342-5645-0057-000001c9d682&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2014-07-10T00:44:55Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''subcategory_num''': (number) This is a sub category for the device.&lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP address and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. tostring(v2))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return true&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== variable: event_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the notification/event server. On UI5 it can be either ''cms1.mios.com'' or ''cms2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: ra_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the remote access server. Can be either ''fwd1.mios.com'' or ''fwd2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: pk_accesspoint ===&lt;br /&gt;
&lt;br /&gt;
type: number&lt;br /&gt;
&lt;br /&gt;
Contains the serial number of this Vera.&lt;br /&gt;
&lt;br /&gt;
=== variable: hw_key ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the Vera hardware key.&lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, is_ready returns true. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;incoming&amp;gt; block that only processes data if is_ready(lul_device) is true.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP 'service' + 'variable' will be set to the 'value' for this device. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: value (string) and Unix time stamp (number) of when the variable last changed&lt;br /&gt;
&lt;br /&gt;
Returns the value of the UPnP service + variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). If the service+variable or device does not exist, it returns nothing.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[Example usage]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value, tstamp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value .. &amp;quot; last changed (Epoch): &amp;quot; .. tstamp)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The device parameter: if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
[[Caution - Incorrect usages]]&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tonumber(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt; also accepts two parameters. However the parameters are incompatible: the Unix timestamp returned by &amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; is being used as a number base in the function &amp;lt;code&amp;gt;tonumber&amp;lt;/code&amp;gt;. The number base is limited to a power of 36 or less and the current timestamps are in the range of thousands of millions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = tostring(luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;luup.variable_get&amp;lt;/code&amp;gt; returns two parameters and &amp;lt;code&amp;gt;tostring&amp;lt;/code&amp;gt; only expects one&lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: string or none  (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If nothing is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code logs nil if theDeviceNumber is invalid.&lt;br /&gt;
local theName = luup.attr_get ('name', theDeviceNumber)&lt;br /&gt;
luup.log(theName)&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code fails if theDeviceNumber is invalid.&lt;br /&gt;
luup.log(luup.attr_get ('name', theDeviceNumber))&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: ip_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the IP address for a device.  This is better than setting the &amp;quot;ip&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: mac_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the mac address for a device.  This is better than setting the &amp;quot;mac&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: reload ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Reloads the Luup engine.&lt;br /&gt;
&lt;br /&gt;
=== function: create_device ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* internal_id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* upnp_file (string)&lt;br /&gt;
* upnp_impl (string)&lt;br /&gt;
* ip (string)&lt;br /&gt;
* mac (string)&lt;br /&gt;
* hidden (boolean)&lt;br /&gt;
* invisible (boolean)&lt;br /&gt;
* parent (number)&lt;br /&gt;
* room (number)&lt;br /&gt;
* pluginnum (number)&lt;br /&gt;
* statevariables (string)&lt;br /&gt;
* pnpid (number)&lt;br /&gt;
* nochildsync (string)&lt;br /&gt;
* aeskey (string)&lt;br /&gt;
* reload (boolean)&lt;br /&gt;
* nodupid (boolean)&lt;br /&gt;
&lt;br /&gt;
returns: the device ID&lt;br /&gt;
&lt;br /&gt;
This creates the device with the parameters given, and returns the device ID.&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string and content_type it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the Smartphone Web Interface plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    local lul_content_type = &amp;quot;text/html&amp;quot;&lt;br /&gt;
    return lul_html, lul_content_type&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above.&lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
=== function: job_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever a job is created, finished, or changes state then ''function_name'' will be called.  If the device is nil or not specified, ''function_name'' will be called for all jobs, otherwise only for jobs that involve the specified device.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;)&lt;br /&gt;
  luup.job_watch(&amp;quot;mycallback&amp;quot;,6)&lt;br /&gt;
&lt;br /&gt;
The first one registers a callback for all devices, the second one only for device 6.  Note that multiple registrations will result in multiple callbacks, so two calls like that means that &amp;quot;mycallback&amp;quot; would be called once for all devices except 6, and for 6 it would be called twice.&lt;br /&gt;
&lt;br /&gt;
The callback function will be passed a table which contains:&lt;br /&gt;
&lt;br /&gt;
device_num: the number of the device&lt;br /&gt;
&lt;br /&gt;
status: the job status, 0-7 as follows&lt;br /&gt;
&lt;br /&gt;
  WaitingToStart=0&lt;br /&gt;
  InProgress=1&lt;br /&gt;
  Error=2&lt;br /&gt;
  Aborted=3&lt;br /&gt;
  Done=4&lt;br /&gt;
  WaitingForCallback=5&lt;br /&gt;
  Requeue=6&lt;br /&gt;
  InProgressPendingData=7&lt;br /&gt;
&lt;br /&gt;
name: the name of the job&lt;br /&gt;
&lt;br /&gt;
type: the C++ class name for the type of job&lt;br /&gt;
&lt;br /&gt;
notes: any notes or progress that set for the job&lt;br /&gt;
&lt;br /&gt;
Here is an example of the callback:&lt;br /&gt;
&lt;br /&gt;
  function mycallback(lul_job)&lt;br /&gt;
    luup.log(&amp;quot;mycallback device #&amp;quot; .. lul_job.device_num .. &amp;quot; status &amp;quot; .. lul_job.status .. &amp;quot; name &amp;quot; .. lul_job.name .. &amp;quot; type &amp;quot; .. lul_job.type .. &amp;quot; notes &amp;quot; .. lul_job.notes);&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
and here is the output in LuaUPnP.log from the above function when it is registered to watch a ZWave device which was turned ON:&lt;br /&gt;
&lt;br /&gt;
  50      07/09/14 17:43:43.491   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E998D0&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.492   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes  &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.493   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.520   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.543   luup_log:3: mycallback device #6 status 0 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.544   luup_log:3: mycallback device #6 status 1 name ON node 2 type ZWJob_SendData notes Waiting to send again with ack &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.545   luup_log:3: mycallback device #6 status 7 name ON node 2 type ZWJob_SendData notes Sending the Z-Wave command after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.576   luup_log:3: mycallback device #6 status 5 name ON node 2 type ZWJob_SendData notes Waiting for node to reply after 0 retries &amp;lt;00E93328&amp;gt;&lt;br /&gt;
  50      07/09/14 17:43:43.631   luup_log:3: mycallback device #6 status 4 name ON node 2 type ZWJob_SendData notes Transmit was ok &amp;lt;00E92A58&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service ID (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (int), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]]&lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to 1 if the device is failing, 0 if it's working, and 2 if the device is reachable but there's an authentication error. If device is a string it is interpreted as a udn, if it's a number, as a device id. The lu_status URL will show for the device: &amp;lt;tooltip display=&amp;quot;1&amp;quot; tag2=&amp;quot;Lua Failure&amp;quot;/&amp;gt; and Lua Failure is shown in red in UI5 for the device.&lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if it's past sunset and before sunrise, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with os.time to see how long it will be for the next event.  luup.sunset-os.time is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
required firmware: 1.5.353&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ptr (binary object), id (string), description (string), device_type (string), device_filename (string), implementation_filename (string), parameters (string), embedded (boolean) [, invisible (boolean)]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to device.&lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the luup.chdev.start call. Give each child a unique id so you can keep track of which is which. You can optionally provide a description which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
device_type is the UPnP device type, such as urn:schemas-upnp-org:device:BinaryLight:1.&lt;br /&gt;
&lt;br /&gt;
If device_filename is specified, that is the name of the&amp;amp;nbsp;XML file with the UPnP device specification. The deviceType from the filename will override any device_type you set manually. If the device_file contains the implementation file for this child device you do not need to specify it in implementation_filename. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in implementation_filename.&lt;br /&gt;
&lt;br /&gt;
If embedded is true, the 'embedded' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The parameters are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a, and = to separate service, variable and value, like this: service,variable=value\nservice...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
io.open&amp;lt;br/&amp;gt;&lt;br /&gt;
io.write&amp;lt;br/&amp;gt;&lt;br /&gt;
io.intercept&amp;lt;br/&amp;gt;&lt;br /&gt;
io.read&amp;lt;br/&amp;gt;&lt;br /&gt;
io.is_connected&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]], ip (string), port (number), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port.&lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean) &lt;br /&gt;
&lt;br /&gt;
In Lua a string can contain binary data, so data may be a binary block. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nill if an error occurred.&lt;br /&gt;
&lt;br /&gt;
The written data is modified depending upon the value of the [[Luup_Plugins_ByHand#&amp;lt;protocol&amp;gt;|&amp;lt;protocol&amp;gt; tag]].&lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), [[Luup_Lua_extensions#device:_string_or_number|device (string or number)]] &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job.&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
=== device: string or number ===&lt;br /&gt;
*If a number, it is the device ID&lt;br /&gt;
*If a string, it is the UDN for the UPnP device&lt;br /&gt;
Both of these can be found in the User Interface (UI5) under the advanced Tab as &amp;quot;id&amp;quot; and &amp;quot;local_udn&amp;quot; respectively.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,87)&lt;br /&gt;
local update_frequency = luup.variable_get(&amp;quot;S_WebcamDropboxUploaderSettings1.xml&amp;quot;,&amp;quot;SendFrequency&amp;quot;,&amp;quot;uuid:4d494342-5342-5645-0057-000001c9d682&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Fibaro_Flood_Sensor_FGFS-101</id>
		<title>Fibaro Flood Sensor FGFS-101</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Fibaro_Flood_Sensor_FGFS-101"/>
				<updated>2014-06-28T19:40:00Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This sensor supports 2 types of tamper alarms, for the tamper switch and the tilt.  However, they do not use the official Z-Wave alarm types, and both use the generic alarm type, so they are both reported as a tamper.  Set variable #74 to 0 to turn these tamper alerts off.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Fibaro_Flood_Sensor_FGFS-101</id>
		<title>Fibaro Flood Sensor FGFS-101</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Fibaro_Flood_Sensor_FGFS-101"/>
				<updated>2014-06-28T19:22:40Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;This sensor supports 2 types of tamper alarms, for the tamper switch and the tilt.  However, they do not use the official Z-Wave alarm types.  They only send a 'generic alarm'...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This sensor supports 2 types of tamper alarms, for the tamper switch and the tilt.  However, they do not use the official Z-Wave alarm types.  They only send a 'generic alarm' type of 0, so there is no way to know the type of tamper, and it is treated as a generic alarm, which in this indicates a flood.  Therefore by default variable #74 is set to 0 to turn these tamper alerts off.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Windows_Serial_Port_ZWave</id>
		<title>Windows Serial Port ZWave</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Windows_Serial_Port_ZWave"/>
				<updated>2014-06-23T21:32:51Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want to use the ZWave module on your Vera as a COM port on a windows PC, run these on the &lt;br /&gt;
&lt;br /&gt;
 killall Start_NetworkMonitor.sh Start_LuaUPnP.sh NetworkMonitor LuaUPnP&lt;br /&gt;
 ser2net -n  -C &amp;quot;3482:raw:0:/dev/ttyS0:115200 1STOPBIT NONE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Then on windows install Serial/IP Redirector from:&lt;br /&gt;
tacticalsoftware.com&lt;br /&gt;
&lt;br /&gt;
It installs something in the toolbar, although you may have to go to program files x86 and run the configuration .exe and add a com port.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Windows_Serial_Port_ZWave</id>
		<title>Windows Serial Port ZWave</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Windows_Serial_Port_ZWave"/>
				<updated>2014-04-01T14:51:17Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;If you want to use the ZWave module on your Vera as a COM port on a windows PC, run these on the   killall Start_NetworkMonitor.sh Start_LuaUPnP.sh NetworkMonitor LuaUPnP ser2...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want to use the ZWave module on your Vera as a COM port on a windows PC, run these on the &lt;br /&gt;
&lt;br /&gt;
killall Start_NetworkMonitor.sh Start_LuaUPnP.sh NetworkMonitor LuaUPnP&lt;br /&gt;
ser2net -n  -C &amp;quot;3482:raw:0:/dev/ttyS0:115200 1STOPBIT NONE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Then on windows install Serial/IP Redirector from:&lt;br /&gt;
tacticalsoftware.com&lt;br /&gt;
&lt;br /&gt;
It installs something in the toolbar, although you may have to go to program files x86 and run the configuration .exe and add a com port.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ThermostatModes</id>
		<title>ThermostatModes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ThermostatModes"/>
				<updated>2014-02-05T21:23:54Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;The user interface exposes the basic commonly used thermostat modes.  However, there are some extra modes which some thermostats may support that are not shown in the UI.  To ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The user interface exposes the basic commonly used thermostat modes.  However, there are some extra modes which some thermostats may support that are not shown in the UI.  To use them, you will need to create a scene, and under the Advanced tab, choose the thermostat, then for the list of commands, under the heading &amp;quot;urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;quot; choose the action &amp;quot;SetModeTarget&amp;quot;, and in the variable &amp;quot;NewModeTarget&amp;quot;, enter one of the following strings without the &amp;quot; marks.  You can then run the scene to go into the mode.:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auxiliary&amp;quot; which is ZWave thermostat mode #4&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Resume&amp;quot; which is ZWave thermostat mode #5&lt;br /&gt;
&lt;br /&gt;
&amp;quot;FanOnly&amp;quot; which is ZWave thermostat mode #6&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Furnace&amp;quot; which is ZWave thermostat mode #7&lt;br /&gt;
&lt;br /&gt;
&amp;quot;DryAir&amp;quot; which is ZWave thermostat mode #8&lt;br /&gt;
&lt;br /&gt;
&amp;quot;MoistAir&amp;quot; which is ZWave thermostat mode #9&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto2&amp;quot; which is ZWave thermostat mode #10&lt;br /&gt;
&lt;br /&gt;
&amp;quot;EnergySaveHeat&amp;quot; which is ZWave thermostat mode #11&lt;br /&gt;
&lt;br /&gt;
&amp;quot;EnergySaveCool&amp;quot; which is ZWave thermostat mode #12&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Away&amp;quot; which is ZWave thermostat mode #13&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auxiliary&amp;quot; which is ZWave thermostat mode #4&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auxiliary&amp;quot; which is ZWave thermostat mode #4&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2013-12-03T00:02:06Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* function: set_failure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''subcategory_num''': (number) This is a sub category for the device.&lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP address and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. tostring(v2))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return true&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== variable: event_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the notification/event server. On UI5 it can be either ''cms1.mios.com'' or ''cms2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: ra_server ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the remote access server. Can be either ''fwd1.mios.com'' or ''fwd2.mios.com''.&lt;br /&gt;
&lt;br /&gt;
=== variable: pk_accesspoint ===&lt;br /&gt;
&lt;br /&gt;
type: number&lt;br /&gt;
&lt;br /&gt;
Contains the serial number of this Vera.&lt;br /&gt;
&lt;br /&gt;
=== variable: hw_key ===&lt;br /&gt;
&lt;br /&gt;
type: string&lt;br /&gt;
&lt;br /&gt;
Contains the Vera hardware key.&lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, &amp;lt;tt&amp;gt;is_ready&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;tt&amp;gt;&amp;lt;incoming&amp;gt; block&amp;lt;/tt&amp;gt; that only processes data if &amp;lt;tt&amp;gt;is_ready(lul_device)&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; parameter, if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device, which, if it's a string, is interpreted as a udn, and if it's a number, is the device number. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), device (string or number), [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP service+variable will be set to value for device, which if it's a string, is interpreted as a udn, and if it's a number, as a device id. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) and time (number) or none (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Returns the value of the UPnP service+variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). If the service+variable or device does not exist, it returns nothing. You can assign just the value to a variable, as follows:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: string or none  (note: none means nothing at all. It does not mean 'nil')&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If nothing is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code logs nil if theDeviceNumber is invalid.&lt;br /&gt;
local theName = luup.attr_get ('name', theDeviceNumber)&lt;br /&gt;
luup.log(theName)&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;-- This code fails if theDeviceNumber is invalid.&lt;br /&gt;
luup.log(luup.attr_get ('name', theDeviceNumber))&lt;br /&gt;
return true&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: ip_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the IP address for a device.  This is better than setting the &amp;quot;ip&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: mac_set ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: value (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Sets the mac address for a device.  This is better than setting the &amp;quot;mac&amp;quot; attribute using attr_set because it updates internal values additionally, so a reload isn't required.&lt;br /&gt;
&lt;br /&gt;
=== function: reload ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: none&lt;br /&gt;
&lt;br /&gt;
Reloads the Luup engine.&lt;br /&gt;
&lt;br /&gt;
=== function: create_device ===&lt;br /&gt;
&lt;br /&gt;
''&amp;lt;span style=&amp;quot;color: red&amp;quot;&amp;gt;Not available in UI5 or lower&amp;lt;/span&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
parameters:&lt;br /&gt;
* device_type (string)&lt;br /&gt;
* internal_id (string)&lt;br /&gt;
* description (string)&lt;br /&gt;
* upnp_file (string)&lt;br /&gt;
* upnp_impl (string)&lt;br /&gt;
* ip (string)&lt;br /&gt;
* mac (string)&lt;br /&gt;
* hidden (boolean)&lt;br /&gt;
* invisible (boolean)&lt;br /&gt;
* parent (number)&lt;br /&gt;
* room (number)&lt;br /&gt;
* pluginnum (number)&lt;br /&gt;
* statevariables (string)&lt;br /&gt;
* pnpid (number)&lt;br /&gt;
* nochildsync (string)&lt;br /&gt;
* aeskey (string)&lt;br /&gt;
* reload (boolean)&lt;br /&gt;
* nodupid (boolean)&lt;br /&gt;
&lt;br /&gt;
returns: the device ID&lt;br /&gt;
&lt;br /&gt;
This creates the device with the parameters given, and returns the device ID.&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string and content_type it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the Smartphone Web Interface plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    local lul_content_type = &amp;quot;text/html&amp;quot;&lt;br /&gt;
    return lul_html, lul_content_type&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above.&lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service ID (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (int), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to 1 if the device is failing, 0 if it's working, and 2 if the device is reachable but there's an authentication error. If device is a string it is interpreted as a udn, if it's a number, as a device id. The lu_status URL will show for the device: &amp;lt;tooltip display=&amp;quot;1&amp;quot; tag2=&amp;quot;Lua Failure&amp;quot;/&amp;gt; and Lua Failure is shown in red in UI5 for the device.&lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: ''true'' if it's past sunset and before sunrise, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with &amp;lt;tt&amp;gt;os.time&amp;lt;/tt&amp;gt; to see how long it will be for the next event.  &amp;lt;tt&amp;gt;luup.sunset-os.time&amp;lt;/tt&amp;gt; is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
required firmware: 1.5.353&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), id (string), description (string), device_type (string), device_filename (string), implementation_filename (string), parameters (string), embedded (boolean) [, invisible (boolean)]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt;. If &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
Pass in the &amp;lt;tt&amp;gt;ptr&amp;lt;/tt&amp;gt; which you received from the &amp;lt;tt&amp;gt;luup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt; which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as &amp;lt;tt&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the&amp;amp;nbsp;XML file with the UPnP device specification. The deviceType from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually. If the device_file contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the 'embedded' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; to separate service, variable and value, like this: &amp;lt;tt&amp;gt;service,variable=value\nservice&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If device is a string it is interpreted as a udn, if it's a number, as a device id. Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
io.open&amp;lt;br/&amp;gt;&lt;br /&gt;
io.write&amp;lt;br/&amp;gt;&lt;br /&gt;
io.intercept&amp;lt;br/&amp;gt;&lt;br /&gt;
io.read&amp;lt;br/&amp;gt;&lt;br /&gt;
io.is_connected&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ip (string), port (number), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port.&lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean) &lt;br /&gt;
&lt;br /&gt;
In Lua a string can contain binary data, so data may be a binary block. If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nill if an error occurred. &lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2012-09-20T18:33:14Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Advanced debugging for developers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.conf (or zwave_products_user.xml?) in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 03 = start/stop/reload events&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Simple</id>
		<title>UI Simple</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Simple"/>
				<updated>2012-09-05T20:52:11Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;br&amp;gt; NOTE: After reading this document to familiarize yourself with the concepts, see [[UI Simple Sample]] which has source code for a free implementation that you can embed within your applications to do all the work. &lt;br /&gt;
&lt;br /&gt;
MIOS is a lightweight home automation system. The 'brain' of the MIOS software is the back-end, the engine, which runs stand-alone on a variety of internet-connected devices, such as PC's, Mac's, Wi-Fi access points, and dedicated home automation gateways. MIOS also includes a portal at mios.com, which acts as secure relay to MIOS systems that may be behind firewalls. Users can register for an account at mios.com, and that account can be linked to one or more MIOS systems to provide the user remote access to his MIOS system from anywhere. It is easy to control a MIOS system with simple http get's (normal internet requests). The URL you will open is generally data_request?id=xxx, where xxx is some sort of request or control command. &lt;br /&gt;
&lt;br /&gt;
This document describes how to create a simple user interface to control a MIOS system using the simplified lu_sdata (LuaUPnP Simple Data) request. This document describes a simple control-only user interface, meaning it let's the user run scenes and control devices, but does not provide any means to change configuration or do advanced tasks. Whatever device is running the user interface (cell phone, web page, television, etc.) will be referred to as the &amp;quot;controller&amp;quot;, and the MIOS engine, or system, that is being controlled by the controller is the &amp;quot;engine&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
You can test out all the commands a normal web browser. For example, if your engine is on the same local network as your web browser, and your engine has the IP address: 192.168.2.150, you can view the status of all scenes and devices by opening this link in your browser: http://192.168.2.150:3480/data_request?id=lu_sdata and if you want to turn on device #5 you open this link in your browser: http://192.168.2.150:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=5&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
The user interface has only two screens, or modes: 1) Basic setup which only consists of identifying the engine the user will control, and 2) Normal usage which consists of running scenes (pre-defined groups of commands), and controlling devices. &lt;br /&gt;
&lt;br /&gt;
A publicly accessible MiOS engine is available on the internet so you can test all these commands as you go. See the section at the end of this document. &lt;br /&gt;
&lt;br /&gt;
== Mode 1: Basic setup and locating the engine  ==&lt;br /&gt;
&lt;br /&gt;
The first thing the user interface should do is find the engine on the internet. There are 2 different ways to control an engine: &lt;br /&gt;
&lt;br /&gt;
1) Directly, using an IP address, where the engine is either on the same local area network as the controller or has a static IP or port forward that's publicly accessible from the internet, such as in the example links above. &lt;br /&gt;
&lt;br /&gt;
2) Through one of the MIOS secure forward servers, which acts as a relay to an engine that may be behind a firewall. The URL is identical except that instead of using the IP you use a mios forward server followed by the /username/password/serial_number, where the username/password are from the user's mios.com account that he linked to his engine, and serial_number is the unique id of the engine. So, assuming you want to turn on device #5 on engine #10266 and the user linked it his mios account with the username &amp;quot;john&amp;quot; and password &amp;quot;tokyo&amp;quot;, you would open this URL (note it's identical to the URL above): https://fwd2.mios.com/john/tokyo/10266/data_request?id=lu_action&amp;amp;amp;DeviceNum=5&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
NOTE: DeviceNum is the '''Device number''' of the device you want to control (found on the Settings tab: e.g. '''Device #5''') and not the ID number.&lt;br /&gt;
&lt;br /&gt;
NOTE: Because method #2 is much slower than method #1 when both the engine and the controller are on the same network, it is generally preferred to use method #1 when the controller is in the home, and method #2 when the controller is away from the home and needs to talk to the engine through the homeowner's firewall. If you are putting your UI in something that is only on a local network, like a TV, and you do not want to give the user the ability to control an engine outside the home, you may only implement method #1. If the UI is running on something that a mobile phone that has NO wi-fi and can only connect through the mobile network, then you may want to implement method #2 only. Normally, though, a user interface should be able to use both method #1 and method #2, and this is how we spec it for our UI's. &lt;br /&gt;
&lt;br /&gt;
When the controller first starts, display this: &lt;br /&gt;
&lt;br /&gt;
 Enter your mios.com username: [__input_box__] [go]&lt;br /&gt;
 __I don't have a mios.com account or I want to specify the IP address.__&lt;br /&gt;
&lt;br /&gt;
Where [go] is a button, [__input_box__] is for the user to type in the username, and the __I don't have... is a link, or button, or similar. If the user clicks the 'I don't have' link, display this: &lt;br /&gt;
&lt;br /&gt;
 Enter the IP: [__input_box__]  [go]&lt;br /&gt;
&lt;br /&gt;
When the user clicks 'go' attempt to the open this url: http://ip:3480/data_request?id=lu_alive (substitute the actual IP), and if you get back an &amp;quot;OK&amp;quot; in the response, store the IP address in your controller locally (ie a conf file, registry, etc) and continue to the next step. If you don't get an OK, display an error and go back. &lt;br /&gt;
&lt;br /&gt;
If the user supplied a mios.com username, open this URL: http://sta1.mios.com/locator_json.php?username=user (substitute 'user' for the actual username). This will return a list of all the engines you can control, both with method #1 and with method #2, meaning you will see both engines on the local network which may or may not be tied to the user's mios.com account, and you will see engines tied to the mios.com account which may or may not be on the local network. As with most of the requests, the returned data is in JSON format. The data you get back is not formatted with new lines and spaces. If you want to be more human readable for debugging, copy/paste the results into http://jsonlint.com and it will format it nicely. The controller needs to have a json library so it can parse the json responses. The data you get back will be like this: &lt;br /&gt;
&lt;br /&gt;
    &amp;quot;units&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;serialNumber&amp;quot;: &amp;quot;10266&amp;quot;,&lt;br /&gt;
           &amp;quot;FirmwareVersion&amp;quot;: &amp;quot;1.1.1052&amp;quot;,&lt;br /&gt;
           &amp;quot;ipAddress&amp;quot;: &amp;quot;192.168.2.117&amp;quot;,&lt;br /&gt;
           &amp;quot;name&amp;quot;: &amp;quot;skyvera&amp;quot;,&lt;br /&gt;
           &amp;quot;users&amp;quot;: [&lt;br /&gt;
               &amp;quot;skyvera&amp;quot;,&lt;br /&gt;
               &amp;quot;aaronb&amp;quot;&lt;br /&gt;
           ],&lt;br /&gt;
           &amp;quot;active_server&amp;quot;: &amp;quot;fwd2.mios.com&amp;quot;,&lt;br /&gt;
           &amp;quot;forwardServers&amp;quot;: [&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd2.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: true&lt;br /&gt;
               },&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd1.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: false&lt;br /&gt;
               }&lt;br /&gt;
           ]&lt;br /&gt;
       },&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;serialNumber&amp;quot;: &amp;quot;8035&amp;quot;,&lt;br /&gt;
           &amp;quot;FirmwareVersion&amp;quot;: &amp;quot;1.1.1047&amp;quot;,&lt;br /&gt;
           &amp;quot;ipAddress&amp;quot;: &amp;quot;192.168.2.116&amp;quot;,&lt;br /&gt;
           &amp;quot;users&amp;quot;: [&lt;br /&gt;
               &amp;quot;ovidiu&amp;quot;,&lt;br /&gt;
               &amp;quot;alfonsomios&amp;quot;,&lt;br /&gt;
               &amp;quot;aaronb&amp;quot;,&lt;br /&gt;
               &amp;quot;mrhtn&amp;quot;&lt;br /&gt;
           ],&lt;br /&gt;
           &amp;quot;active_server&amp;quot;: &amp;quot;fwd1.mios.com&amp;quot;,&lt;br /&gt;
           &amp;quot;forwardServers&amp;quot;: [&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd1.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: true&lt;br /&gt;
               },&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd2.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: false&lt;br /&gt;
               }&lt;br /&gt;
           ]&lt;br /&gt;
       },&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;serialNumber&amp;quot;: &amp;quot;10516&amp;quot;,&lt;br /&gt;
           &amp;quot;FirmwareVersion&amp;quot;: &amp;quot;1.1.1047&amp;quot;,&lt;br /&gt;
           &amp;quot;ipAddress&amp;quot;: &amp;quot;192.168.2.23&amp;quot;,&lt;br /&gt;
           &amp;quot;users&amp;quot;: [&lt;br /&gt;
               &lt;br /&gt;
           ],&lt;br /&gt;
           &amp;quot;active_server&amp;quot;: &amp;quot;fwd2.mios.com&amp;quot;,&lt;br /&gt;
           &amp;quot;forwardServers&amp;quot;: [&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd2.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: true&lt;br /&gt;
               },&lt;br /&gt;
               {&lt;br /&gt;
                   &amp;quot;hostName&amp;quot;: &amp;quot;fwd1.mios.com&amp;quot;,&lt;br /&gt;
                   &amp;quot;primary&amp;quot;: false&lt;br /&gt;
               }&lt;br /&gt;
           ]&lt;br /&gt;
       }&lt;br /&gt;
   ]&lt;br /&gt;
&lt;br /&gt;
units is an array of JSON objects, one representing each engine. If the tag ipAddress exists for an engine, that means it's available on the local network and can be controlled locally with method #1, otherwise the ipAddress tag will not exist. The users array is a list of all the mios.com usernames which have access to this engine. So, if the username you passed on the locator_json.php URL is also in the users array, then the engine can be controlled remotely with the username, using whatever server is listed in the &amp;quot;active_server&amp;quot; tag. The forwardServers tag lists the primary server for remote access and one or more backups. If the tag &amp;quot;name&amp;quot; exists, that is a name which the user assigned to his engine. &lt;br /&gt;
&lt;br /&gt;
If you cannot get a response from sta1.mios.com, try sta2.mios.com. They are mirrored servers with the same data but in different data centers for redundancy. &lt;br /&gt;
&lt;br /&gt;
The next screen in the UI should say &amp;quot;What MiOS engine do you want to control?&amp;quot; and then display a list of all the engines with both the serialNumber and name if it exists. You should have 2 icons next to each for 'remote' and 'local' access. In the above example, assuming the username I passed in is &amp;quot;skyvera&amp;quot; 10516 will have the 'local' icon only, since there are no users, and for 8035 it will also be 'local' only because skyvera is not one of the allowed users. For 10266 display both the 'remote' and 'local' icon. At the bottom of the page you can have a legend: &lt;br /&gt;
&lt;br /&gt;
[R icon] - You can access this MiOS engine from anywhere in the world over the internet using your mios.com account &lt;br /&gt;
&lt;br /&gt;
[L icon] - You can access this MiOS engine locally on your home network without going through your mios.com account &lt;br /&gt;
&lt;br /&gt;
And also a multiple choice asking the user if he wants: Automatic connection, Local connection only, or Remote connection only. &lt;br /&gt;
&lt;br /&gt;
Let the user pick the engine he wants to control and store in the controller's local storage the username supplied by the user, and from the JSON file for whatever engine the user picked store the contents of serialNumber, ipAddress, active_server, and store the list of servers in forwardServers. &lt;br /&gt;
&lt;br /&gt;
At this point display: &lt;br /&gt;
&lt;br /&gt;
  mios.com password: [__input_box__]&lt;br /&gt;
 [ ] Store my password so I don't have to enter it each time&lt;br /&gt;
 [go]&lt;br /&gt;
&lt;br /&gt;
If the user checks the box, store the password. When the user clicks go, if you stored an ipaddress, test it with: &lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=lu_alive &lt;br /&gt;
&lt;br /&gt;
and confirm you get an OK. Then test the password with: &lt;br /&gt;
&lt;br /&gt;
https://xxx.mios.com/username/password/serial/data_request?id=lu_alive and substitute xxx.mios.com for the active_server, and substitute the actual username/password/serial. Again, confirm you get back an OK. &lt;br /&gt;
&lt;br /&gt;
If you do not get an OK for both (or the 2nd one if there was no local ip address), display an error and go back: &lt;br /&gt;
&lt;br /&gt;
 Unable to connect.  Please check your password.  [ok]&lt;br /&gt;
&lt;br /&gt;
== Mode 2: Normal operation  ==&lt;br /&gt;
&lt;br /&gt;
Now that you have stored the connection information (ip address, etc.), you can start the main application. From now on, whenever the user starts the UI, it should go straight into the main application and not ask him for the connection information again, although within the normal operation the user has the option of returning to setup. &lt;br /&gt;
&lt;br /&gt;
The use can choose to control ''devices'' and ''scenes''. A device is a light switch, a thermostat, a door lock, etc. Some devices may not have any control options, meaning the user cannot do anything with them, and they are only there to show status, such as a motion sensor or a temperature sensor. Scenes simply groups of actions the user has pre-defined, such as &amp;quot;Go to bed&amp;quot;, which may be a scene that turns off all the lights. &lt;br /&gt;
&lt;br /&gt;
The user is able to create ''rooms'' and ''sections'' to organize the devices and scenes. Devices and scenes can be assigned to a room, and each room can be assigned to a section. Only very large home with many rooms divide the rooms into multiple sections, such as &amp;quot;West Wing&amp;quot;, &amp;quot;3rd floor&amp;quot;, etc. By default there is only 1 section and all the rooms belong to it. &lt;br /&gt;
&lt;br /&gt;
Devices and rooms may or may not be assigned to a room. Small installations with only a handful of devices typically do not create rooms, and all the devices and sections are left unassigned. When the user does create rooms, he does not need to assign all devices and sections to a room, so some may remain as unassigned. &lt;br /&gt;
&lt;br /&gt;
Each device has a category, such as 'dimmable light', 'thermostat', 'door lock', and so on. &lt;br /&gt;
&lt;br /&gt;
So, a typical top-level menu may have the following options: &lt;br /&gt;
&lt;br /&gt;
''Setup'' to return to Mode 1 and choose a new engine to connect to. If the user interface has a menu or option button the Setup can be there so it does not occupy space on the main menu. &lt;br /&gt;
&lt;br /&gt;
''Scenes'' This lists all the scenes. First list the scenes not assigned to a room, then list the scenes grouped by the room they are assigned to. &lt;br /&gt;
&lt;br /&gt;
''Lights'', ''Thermostats'', etc. Next the controller lists the categories so the user can just straight to 'thermostats' and see what thermostats, lights, etc. are in the house. The lu_sdata request will provide you with a list of the categories that are actually used in the system. Only display categories that are listed in the 'Status of the device or scene and control buttons' section below. In other words, if you have a device with category #1 (Interface), and there is a category #1 in the lu_sdata, do NOT display it in the user interface. Do not display a button 'Interface', and do NOT display the device with this category anywhere in the UI. Devices that are in the categories shown below should be ignored completely. &lt;br /&gt;
&lt;br /&gt;
''Devices'' This lists all the devices that are not assigned to a room &lt;br /&gt;
&lt;br /&gt;
''Living Room'', ''Bedroom'', etc. Next is a list of all the rooms, broken down by section. Choosing a room lists the scenes in that room, followed by the devices. &lt;br /&gt;
&lt;br /&gt;
Therefore if a device is assigned to a room, it will appear in 2 places, in both the room and in the device's category. The same is true for scenes. Here is a typical top-level menu: &lt;br /&gt;
&lt;br /&gt;
[[Image:Uispec mainmenu.png]] &lt;br /&gt;
&lt;br /&gt;
If the user choose a room that has a binary light, a dimmable light, and a thermostat in it, following is what the sub-menu looks like: &lt;br /&gt;
&lt;br /&gt;
[[Image:Uispec submenu.png]] &lt;br /&gt;
&lt;br /&gt;
The name of the device or scene is the primary identifier along with an icon that depends on the device category. Each device has control options that are specific to the device's category, like 'on' and 'off' for binary light switches, and 'on', 'off' and a slider bar for dimmable light switches. The current status of the device should be indicated both by the status of the icon (light bulb yellow if it's on, gray if it's not), as well as by highlighting the control button corresponding to the status, for example, the 'on' button should be highlighted if the device is on. &lt;br /&gt;
&lt;br /&gt;
Additionally, there should be a space in the device's control or scene's control that is reserved to indicate the 'state' of the device or scene. All devices and scenes can have 1 of the following 4 states: none (nothing is going on with the device or scene), pending (it's actively being controlled), success (the last action performed was successful), error (something is wrong with the device). And, for both scenes and devices there needs to be a way to display a short comment. For large controllers, like a TV, this may mean displaying the comments on the UI whenever they exist. For small displays, like mobile phones, it's possible to have the user touch the device to see more details, such as the comments. &lt;br /&gt;
&lt;br /&gt;
== Software architecture: Two threads with a polling loop  ==&lt;br /&gt;
&lt;br /&gt;
Typically the software for the controller is written with 2 separate threads: 1) the back end: a background poll loop that continuously polls the engine for changes and which updates an object-oriented class structure containing the list of sections, rooms, scenes and devices, as well as the state of the engine (ip address, running state, etc.), and 2) the front end: the user interface which displays the data retrieved by the poll loop. &lt;br /&gt;
&lt;br /&gt;
These should be separate as much as possible with separate classes. That way it's possible to reskin the user interface at some point without having to rewrite the poll loop. The poll loop has no user interface and simply runs as a separate thread and just continuously polls the engine. The user interface should be separate from the poll loop so it can be replaced easily. &lt;br /&gt;
&lt;br /&gt;
Both the back end and front end need to access the same object oriented class structure and need to be able to operate completely independently, so separate threads and mutex's are required. &lt;br /&gt;
&lt;br /&gt;
Just like devices and scenes can have 4 different &amp;quot;states&amp;quot;, the engine itself also has the same 4 states: none, pending, success, error. &lt;br /&gt;
&lt;br /&gt;
As mentioned, the back end (polling loop) creates a class structure which the front end renders, and one of the things in the class structure is the state of the engine. This should be stored as a signed integer, and the initial value will be -2, which always means 'not connected'. When the front end (the user interface) starts up and sees the engine state is -2 (not connected) it should display a 'Please wait. Connecting...' message. &lt;br /&gt;
&lt;br /&gt;
== lu_sdata: The polling loop  ==&lt;br /&gt;
&lt;br /&gt;
The back end is simply a polling loop that continuously requests the &amp;quot;lu_sdata&amp;quot; data_request from the engine. This is done by fetching the following URL: http://ip/data_request?id=lu_sdata &lt;br /&gt;
&lt;br /&gt;
As mentioned in the beginning, you can use the IP address of the engine directly and always use port 3480, like this: &lt;br /&gt;
&lt;br /&gt;
http://192.168.2.117:3480/data_request?id=lu_sdata &lt;br /&gt;
&lt;br /&gt;
or you can connect remotely through the forward servers, like this: &lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/john/tokyo/10266/data_request?id=lu_sdata &lt;br /&gt;
&lt;br /&gt;
You should always connect directly whenever possible. In addition to storing the state of the engine in a shared variable, the back end should also store in a variable if it is connected directly or remotely through the forward server, and the user interface will display an icon indicating if it is connected directly or remotely. If the direct connection fails, you should automatically switch over to the remote connection. Once the network settings have changed, for example, a mobile phone has switched from 3G to Wi-Fi, try again the direct connection. &lt;br /&gt;
&lt;br /&gt;
To make development easier, if you are using Firefox, which has a built-in xml parser, you can add an &amp;quot;output_format=xml&amp;quot; to the URL and the engine will convert the json to xml, which Firefox renders nicely. This is only for testing. Your actual controller must always retrieve everything in the native json format. &lt;br /&gt;
&lt;br /&gt;
For example, MIOS has an engine available to outside developers on a static IP (76.168.224.30). The following URL will show the lu_sdata reformatted as xml in Firefox: &lt;br /&gt;
&lt;br /&gt;
http://76.168.224.30:3480/data_request?id=lu_sdata&amp;amp;amp;output_format=xml &lt;br /&gt;
&lt;br /&gt;
You can use this for developing your user interface too, just drop the &amp;amp;amp;output_format=xml and if you want to format the JSON nicely, visit jsonlint.com. &lt;br /&gt;
&lt;br /&gt;
Note the top-level object contains these tags: &lt;br /&gt;
&lt;br /&gt;
full=&amp;quot;1&amp;quot; loadtime=&amp;quot;1282441735&amp;quot; dataversion=&amp;quot;441736333&amp;quot; state=&amp;quot;-1&amp;quot; comment=&amp;quot;&amp;quot; &lt;br /&gt;
&lt;br /&gt;
full is either 0 or 1, and 1 means lu_sdata has returned the complete list of sections, rooms, devices and scenes. If full is 0, the lu_sdata is only returning the devices and scenes which have changed since the last request. On subsequent calls to lu_sdata you will get the loadtime and dataversion back on the URL, like this: &lt;br /&gt;
&lt;br /&gt;
http://76.168.224.30:3480/data_request?id=lu_sdata&amp;amp;amp;loadtime=1282441735&amp;amp;amp;dataversion=441736333 &lt;br /&gt;
&lt;br /&gt;
The state is the state of the engine. It is the same as the state of the devices and scenes. See &amp;quot;List of states&amp;quot; below to see what the numbers mean. If the state is not 'none', the main menu should display at the top a red, green or blue icon (for error, success or pending states) and show the user what is in the comment tag. &lt;br /&gt;
&lt;br /&gt;
Next are all the device categories listed in an array. Each category has a name and an id tag, like this: name=&amp;quot;Thermostat&amp;quot; id=&amp;quot;5&amp;quot;. You will only see the categories for devices that exist in the MIOS installation. Always use the id for internal reference; the name changes based on the user's language. &lt;br /&gt;
&lt;br /&gt;
Next are all the sections listed in an array. Each section has a name and an id tag, like this: name=&amp;quot;My Home&amp;quot; id=&amp;quot;1&amp;quot; Again, in most homes, there is only 1 section, and, if there is only 1 section, you do not need to show this to the user. &lt;br /&gt;
&lt;br /&gt;
Next are the rooms. Again, they have a name and an id, and also a section which the room is in. &lt;br /&gt;
&lt;br /&gt;
Next are the scenes. Scenes also have a name and an id. They also have an 'active' of either 0 or 1. If the active is '1', that means the scene is currently active, meaning all the devices are presently in the state the scene will set. So if the scene is 'go to bed', and it turns off all the lights, and if all the lights are currently off, 'active' will be 1 for the scene whether or not the user recently ran the scene. Scenes also have a state and comment (see state list below). The back end (polling loop) actually doesn't do anything with the active, state or comment other than store then in shared objects or variables that the front end (the user interface) uses to render the controls for the user. &lt;br /&gt;
&lt;br /&gt;
Next are the devices. They also have the name, id, state and comment, plus they have a category. Additionally, they have extra tags which depend on the category of device. Light switches, for example, will have a 'status' tag and a value of 0 or 1 indicating if the light is off or on. Thermostats also have a 'temperature' tag. See the 'categories' section below. &lt;br /&gt;
&lt;br /&gt;
The polling loop continues to repeat indefinitely as long as the application is running. Each time it passes the loadtime and dataversion of the prior request. Additionally, you should add a timeout argument to the url. This is the number of seconds that the URL will block waiting for a change. For example, this URL: &lt;br /&gt;
&lt;br /&gt;
http://76.168.224.30:3480/data_request?id=lu_sdata&amp;amp;amp;loadtime=1282441735&amp;amp;amp;dataversion=441736333&amp;amp;amp;timeout=60 &lt;br /&gt;
&lt;br /&gt;
Will block for a maximum of 60 seconds if no devices or scenes have changed since the loadtime=1282441735&amp;amp;amp;dataversion=441736333. The timeout should be as large as is reasonable to minimize the amount of traffic between the controller and the engine, but small enough to ensure the socket libraries in the controller do not time out and exit with an error before the 'timeout' number of seconds has passed. &lt;br /&gt;
&lt;br /&gt;
Additionally you should add a minimumdelay to the argument which is the number of millseconds that the engine will block the request even if there are changes. For example: &lt;br /&gt;
&lt;br /&gt;
http://76.168.224.30:3480/data_request?id=lu_sdata&amp;amp;amp;loadtime=1282441735&amp;amp;amp;dataversion=441736333&amp;amp;amp;timeout=60&amp;amp;amp;minimumdelay=2000 &lt;br /&gt;
&lt;br /&gt;
means that the request will block for up to 60 seconds and if a change occurs after the request has been blocking 2 seconds, the request will return instantly. But if the change has already occurred or occurs in less than 2 seconds, the engine will make sure the request blocks at least 2 seconds before returning. The reason for this is that often there is a flurry of changes in rapid succession. For example if a user runs a scene that turns on 20 lights, without the minimumdelay, lu_sdata would be constantly incrementing the dataversion and returning immediately for several seconds while the scene is running, and it would max out the cpu of both the engine and the controller having constant polls. &lt;br /&gt;
&lt;br /&gt;
If the last lu_sdata request failed to return anything, then you must introduce your own delay to prevent from bogging down the controller or engine in a constant polling loop. &lt;br /&gt;
&lt;br /&gt;
On the initial request it is harmless to pass in 0's for the loadtime and dataversion. This is the same as omiting them and means you will receive the full set of data. Also, when the user has made changes to his configuration, like renaming a device, adding a device, scene or room, etc., the loadtime value will change and you will get a full set of data also (full=1). While the engine is running, status changes only, like a light going on and off, etc., will only increment the dataversion. So when you pass in a value for loadtime, if it still matches the current loadtime timestamp of the engine's configuration, then lu_sdata will not return sections, rooms, or categories, and it will only return the scenes and devices that have changed since the dataversion you passed in. It also will not return the name of the scene or device, since changing the name results in a new loadtime. &lt;br /&gt;
&lt;br /&gt;
Thus the back end poll loop may want to set a 'full' variable to 1 whenever it receives a full set of data, in which case the front end user interface knows to re-render the entire UI. When the poll loop receives partial, or diff, data, it can simply update the internal object or variable that stores the device or scene and set a 'dirty' or 'updated' flag for that scene or device, which is how the front end user interface knows to update that scene or device if it's currently shown on the screen. So, when a device is turned on or off, the poll loop's pending lu_sdata will immediately return with the new state of the device, and if that device is shown on the user interface, the UI should immediately change to reflect the new status of the device. &lt;br /&gt;
&lt;br /&gt;
Following is some pseudo-code showing how the poll loop would typically be written: &lt;br /&gt;
&lt;br /&gt;
 int LoadTime=0;&lt;br /&gt;
 int DataVersion=0;&lt;br /&gt;
 int DefaultTimeout=60;&lt;br /&gt;
 int DefaultMinimumDelay=2000;&lt;br /&gt;
 int CurrentMinimumDelay=0;&lt;br /&gt;
 int CurrentSleep=2000;&lt;br /&gt;
 int EngineState=-2; // Meaning we are not connected&lt;br /&gt;
 string IpAddress; // Will be: &amp;quot;http://76.168.224.30:3480/&amp;quot; or maybe &amp;quot;https://fwd2.mios.com/john/tokyo/10266/&amp;quot;&lt;br /&gt;
 int NumFailures=0;&lt;br /&gt;
 &lt;br /&gt;
 while( Quit==false )&lt;br /&gt;
 {&lt;br /&gt;
 	URL = IpAddress + &amp;quot;data_request?id=lu_sdata&amp;amp;amp;loadtime=&amp;quot; + LoadTime + &amp;quot;&amp;amp;amp;dataversion=&amp;quot; + DataVersion + &amp;quot;&amp;amp;amp;timeout=&amp;quot; + DefaultTimeout + &lt;br /&gt;
 &amp;quot;&amp;amp;amp;minimumdelay=&amp;quot; + CurrentMinimumDelay;&lt;br /&gt;
 	string Data = FetchURL(URL);&lt;br /&gt;
 &lt;br /&gt;
 	// If the request was successful, there will be something in Data&lt;br /&gt;
 	if( Data.IsEmpty() )&lt;br /&gt;
 	{&lt;br /&gt;
 		// Be sure the user knows we're not connected&lt;br /&gt;
 		EngineState=-2;&lt;br /&gt;
 &lt;br /&gt;
 		NumFailures = NumFailures + 1;&lt;br /&gt;
 		if( NumFailures &amp;amp;gt; MAX_FAILURES )&lt;br /&gt;
 		{&lt;br /&gt;
 			CheckConnection();&lt;br /&gt;
 			continue;&lt;br /&gt;
 		}&lt;br /&gt;
 &lt;br /&gt;
 		// The request failed, so sleep a couple seconds before trying again&lt;br /&gt;
 		Sleep(CurrentSleep);&lt;br /&gt;
 &lt;br /&gt;
 		// No need to introduce a minimum delay since this will be the first request&lt;br /&gt;
 		CurrentMinimumDelay=0; &lt;br /&gt;
 		&lt;br /&gt;
 		// Try again&lt;br /&gt;
 		continue;&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
 	// So we have data.  Parse it and update our variables, like the EngineState, LoadTime, DataVersion, and all the scenes, devices, etc.&lt;br /&gt;
 	ParseResponse(Data);&lt;br /&gt;
 &lt;br /&gt;
 	// We got valid data, so introduce the minimumdelay in case there's a flood of changes&lt;br /&gt;
 	CurrentMinimumDelay=DefaultMinimumDelay;&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; The is not complete code, but rather just an outline of the polling process. The assumption here is that there is other initialization code which sets variables, like IpAddress, based on the information from Mode 1/Setup, namely the locating of the engine. while( Quit==false ) means this is a loop that keeps going until the wants to quit the application. In reality when the user chooses to quit you'll need to kill the thread since the FetchURL could be blocking for a while waiting for changes. &lt;br /&gt;
&lt;br /&gt;
On the first pass URL will have loadtime=0 and dataversion=0, meaning we will always get the full list of sections, rooms, etc. So, when ParseResponse parses the json data, it will create all the objects and variables the front end will use to show this to the user. &lt;br /&gt;
&lt;br /&gt;
If the fetching of the URL fails, you should set the engine status back to the initial value of -2, which means the user's UI will be interrupted so he cannot continue, and he'll have a modal 'Please wait... Connecting'. It is normal for the engine to become unavailable for up to 45 seconds or so. For example, if the user just installed some plugins, or saved a bunch of changes, the engine will go offline and stop responding while it's resetting. Therefore, when the fetching of the URL fails the first time you should display the 'Please wait' but don't treat it as an error. That's why we have a if( NumFailures &amp;amp;gt; MAX_FAILURES ), and presumably, since we have a delay of 2 seconds for each request, MAX_FAILURES may be 30 if we want to go to an error condition after 60 seconds of failures. In reality, if FetchURL blocks for a while, having a fixed number of failures, like MAX_FAILURES, may not be good. If FetchURL blocked for 60 seconds, you wouldn't want the user to have a 'Please wait...' for up to 30 minutes. Also, the 'Please wait... Connecting' modal dialog needs to have a 'Quit' and 'Setup' option so the user can exit the app, or go back to the setup part to change his connection. CheckConnection is a function that should take care of a problem by reporting this to the user and letting him check his network settings. In reality, if FetchURL fails, and if you are currently connecting locally, and you are using a mobile phone or other device that can switch from a local connection like wi-fi to a remote connection like 3G, then if you are on a local connection and it suddenly drops, you should right away run a process that checks if the local connection is ok, and if not, switches to the remote connection (ie the https://fwd2.mios.com). Similarly, if the network settings have changed and you were on a remote connection, but now are on wi-fi, you should check if the local connection is ok. This is assuming the user chose the default 'Automatic connection' back on the setup connection page (see: &amp;quot;And also a multiple choice asking the user if he wants: Automatic connection, Local connection only, or Remote connection only.&amp;quot;), otherwise you will need to stick to a remote or local connection only. &lt;br /&gt;
&lt;br /&gt;
If the connection fails, you can reset the minimumdelay on the next request to 0, because there's no reason for the engine to wait a couple seconds before return on a lu_sdata request for initial data; you don't want to slow down the user's experience. But, you need to introduce your own sleep of a couple seconds between requests so you're not maxing out the cpu on the engine or the controller. &lt;br /&gt;
&lt;br /&gt;
In this code, it's assumed ParseResponse is the function that parses the JSON data and creates all the objects and variables in memory which the front end will render for the user. If ParseResponse sees the JSON tag &amp;quot;full&amp;quot;: 1, then it should purge it's list of devices, scenes, rooms, sections, categories, and rebuild them from scratch, and set a flag so the user interface will re-render the new data. ParseResponse also needs to set the dataversion and loadtime that are passed on the next request to whatever just came in on this request. ParseResponse should also set the variable with the state of the engine (EngineState in this example) to the 'state' tag that comes back in the json data. This way the user interface can show the actual state, or the 'Please wait... Connecting' if the state is -2 (ie the controller is not connected to the engine). &lt;br /&gt;
&lt;br /&gt;
If we got a valid response, then the back end should not introduce its own delay, it should simply set the minimumdelay and let the engine handle the delay (CurrentMinimumDelay=DefaultMinimumDelay). This way, you will not introduce any unnecessary latency in the user interface. &lt;br /&gt;
&lt;br /&gt;
== The front end user interface  ==&lt;br /&gt;
&lt;br /&gt;
As mentioned earlier, the front end of the controller should be kept separate from the back end as much as possible so the user interface can be reskinned. It will, however, need to access the objects and variables created by the back end in order to render the UI. When the back end receives a full set of data from lu_sdata (ie full=1) a flag should be set which causes the front end to re-render the entire UI. You should not, however, lose the user's place. If the user had selected &amp;quot;Living Room&amp;quot; and had selected the &amp;quot;Overhead chandalier&amp;quot;, then even if the front end does a full re-render, it should still preserve the user's place. This may not be possible since it's possible the device or room has since been deleted. So the front end does need to take account that during a full re-render, everything may change. &lt;br /&gt;
&lt;br /&gt;
When the back end updates the current state variables for devices and scenes, the front end should update those devices or scenes if they are visible so the user sees the change. As mentioned before, the icon for the device as well as what control button is highlighted should change to reflect the current state. &lt;br /&gt;
&lt;br /&gt;
If there is no physical exit button, then the top level menu needs to have an exit option. &lt;br /&gt;
&lt;br /&gt;
When rendering the scenes and devices, what you show the user is the 'name'. However, what is used internally is the 'id', which is not shown to the user. &lt;br /&gt;
&lt;br /&gt;
There are 2 things you show the user: 1) the state of every device, scene and engine (meaning if the device is busy or has an error condition), and 2) the status of the device or scene (meaning if the device is on or off or what temperature it is), and 3) the control buttons the user uses to control the device or scene. &lt;br /&gt;
&lt;br /&gt;
Number 2 and 3 are really the same. The control buttons for a light switch (ie on and off) also show the status of the light switch (if it's on, then the 'on' button is highlighted). Additionally there may be icons and readouts for to indicate the status. What status a device has, what control buttons it has, and how to display to them user is specific to each category of device. These are explained in the following 2 sections. &lt;br /&gt;
&lt;br /&gt;
== State of engine, device, or scene  ==&lt;br /&gt;
&lt;br /&gt;
The engine itself as well as each device and scene have a 'state' tag which indicates if everything is ok. The lu_sdata returns a number from -1 to 6 to indicate the state. In the user interface, though, you several state numbers are treated the same so you actually have only 4 states to contend with. Note that for the engine only, we've added an extra state -2 which means that you can't talk to the engine, as explained earlier. The 4 states lu_sdata returns are: &lt;br /&gt;
&lt;br /&gt;
NONE: state value is -1. This means there's nothing to report to the user. The device/scene/engine is working ok, and is not doing anything at the moment. &lt;br /&gt;
&lt;br /&gt;
PENDING: state value is 0, 1, 5 or 6. All of those values mean the same 'pending' state. A pending state is always shown in blue. So for devices and scenes there should be a state indicator. When the engine itself has a pending state, display a prominent 'busy' indicator at the top of the UI. Note some of the commands might return errors when the state is busy depending on what device is being controlled and what the engine is busy doing. The value of the 'comment' for the engine, scene or device should be available to the user. &lt;br /&gt;
&lt;br /&gt;
ERROR: state value is 2 or 3. In either case display a red indicator needs to be shown for the engine, scene or device indicating a failure, and display the comment. &lt;br /&gt;
&lt;br /&gt;
SUCCESS: state value is 4. Display a green indicator and the comment. In general the success state is temporary. If you turn on a light, for example, the engine will report the state of the device as SUCCESS for about 30 seconds so the user can see that whatever he did went through ok, and then the state returns to NONE. &lt;br /&gt;
&lt;br /&gt;
== Status of the device or scene and control buttons  ==&lt;br /&gt;
&lt;br /&gt;
This depends on what category of device you are showing. The status tags returned by lu_sdata are different for a thermostat, which has status tags like mode, heatsp, coolsp, etc., than for a light switch with has the status tags level and status. Normally a control button, like the button that turns on a light, if bound to a status so the user can tell by whether the button is highlighted or not if the command is already active. For example, with a light switch, there is a 'status' tag that is 0 or 1 depending on if it's on or off. There are also 2 command buttons: on and off. Those 2 command buttons are bound to the status, meaning that if the status is 0, then the 'off' button should appear highlighted so the user can tell the light is already off. Each control button is tied to a command, like the 'on' button sends the 'on' command to the device. You should always send the command even if the command button is already highlighted. In other words, even if the status of a light is 0 (off) and the off button is already highlighted, when the user selects the off button, send the 'off' command regardless. You send commands by opening a URL on the engine, just like the poll loop does. The difference is that to run a command the data_request is generally &amp;quot;lu_action&amp;quot; instead of &amp;quot;lu_sdata&amp;quot;. The engine is multi-threaded and can handle many requests at once. So you should not interrupt the background polling loop when you want to send a command. The polling loop will continue to block on the lu_sdata request, and, in parallel, the you will do a lu_action request when the user selects a command button. &lt;br /&gt;
&lt;br /&gt;
When the user selects a control button for a device or scene, you will use lu_action to tell the engine what to do. In all cases you will get back either an OK or a JobID inside a response tag. If you don't, you will get back an error message which you should pass to the user. If you don't get anything back, retry the lu_action once every 2 seconds for up to 30 seconds, displaying an hour glass or busy indicator while you do, and, if, after 30 seconds you still cannot get a response to lu_action, report to the user that you lost contact with the engine. It is normal for lu_action to fail if the engine is reloading. So, for example, if the user clicks 'Lock' and you get back the error message &amp;quot;Lock operation is not available&amp;quot;, then display a popup message in the user interface with an 'ERROR' icon and display the message &amp;quot;Lock operation is not available&amp;quot; with an 'OK' button. On the other hand if you do not get any response at all to lu_action, or get an html error, just keep retrying over and over until you either get a response or timeout. &lt;br /&gt;
&lt;br /&gt;
You will always pass a 'service', an 'action', and optionally arguments on lu_action. So you should have a common function, like SendAction(string service, string action, string arguments), which has the logic of sending the command to the engine. To determine what service, action and arguments to use, you can 1) log in with ssh, the root password is the wi-fi password printed on the bottom, and type: ''tail -f /var/log/cmh/LuaUPnP.log | grep ^08'' and then control the device through the web UI. You will see in the console all the service/action/arguments for the commands you're sending. 2) You can also call the data_request lu_invoke, like ''http://__IP__:3480/data_request?id=invoke'' which has a human-readable list of devices and when you click them it shows you the service/action/arguments available. 3) If you understand UPNP terminology, you can go in the Web UI to Apps, Develop Apps, Luup files, and retrieve the actual UPNP XML files. The device files start with D_, and when you click the settings for a device in the web UI, you will see the name of the UPNP device file it uses. &lt;br /&gt;
&lt;br /&gt;
When the user selects a control button, do not automatically show that button highlighted. For example, if a light is 'off' and the user selects 'on', give the user feedback with the 'on' button so he knows his selection was recognized, but do not automatically switch which button is highlighted. The background poll loop will get back a new 'status' for the device when the engine has completed turning off the light. As soon as you send the command with lu_action, the polling loop should immediately return and the state for the device or scene will change to 'PENDING'. This means the user should see the 'blue' busy indicator so he knows the engine is busy controlling the device. When the engine has succeeded in setting the device, the state will change to 'SUCCESS' and the status variable(s) will be changed, and that will cause the UI to re-render the control showing the new status. &lt;br /&gt;
&lt;br /&gt;
Following are the categories, the status codes and the control buttons: &lt;br /&gt;
&lt;br /&gt;
SCENE: There is simply a 'Run' button for the control. The status is active or not active (active=1 or active=0). Scenes only have a 'run' button as the action, and if the scene is active, simply show the 'run' button in a highlighted state. When selected use service &amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot; and action &amp;quot;RunScene&amp;quot; and pass the id of the scene as the SceneNum argument. For example, to run scene id 5, open this request: http://192.168.2.117:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=5 &lt;br /&gt;
&lt;br /&gt;
For devices, refer to the 'category' tag for the device: &lt;br /&gt;
&lt;br /&gt;
CATEGORY #2 - Dimmable Light: 'status' is 0 or 1 for off or on, and if status is 1, 'level' is a value from 0-100 to indicate the brightness. Buttons 'on' and 'off' should be bound to the 'status' for the device, and if selected, should send the service &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot; action &amp;quot;SetTarget&amp;quot; with the argument &amp;quot;newTargetValue&amp;quot; is a value of 0 for off or 1 for on. There should also be a slider which represents the 'level' for the device from 0-100. If the user changes the level, send the service &amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, action &amp;quot;SetLoadLevelTarget&amp;quot; and argument &amp;quot;newLoadlevelTarget&amp;quot; is 0-100. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #3 - Switch: Like dimmable light, but it only has 'status' &lt;br /&gt;
&lt;br /&gt;
CATEGORY #4 - Security Sensor: 'tripped' is 0 or 1 to indicate if the sensor is tripped or not (1=tripped). 'armed' is 0 or 1 to indicate if it's in an armed state. There is a single control button 'ARM'. If the 'armed' status is 1, display the 'ARM' button in a highlighted state, otherwise in a normal state. When the 'ARM' button is selected, this is one case where you do not use lu_action; use lu_variableset instead. ARM is simply a flag in the engine, so use this: http://ip:3480/data_request?id=lu_variableset&amp;amp;amp;DeviceNum=x&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:SecuritySensor1&amp;amp;amp;Variable=Armed&amp;amp;amp;Value=y and replace x with the device id, and replace y with 0 if the armed status is 1, and 1 if it's 0, so the ARM button is a toggle. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #5 - Thermostat: 'fan' is 'auto' if the fan mode is off/normal or 'ContinuousOn' if the fan is always on. 'mode' indicates the mode of the thermostat with options being 'Off', 'HeatOn', 'CoolOn', 'AutoChangeOver'. 'hvacstate' indicates the current state of the thermostat, in other words, if it's in cool mode, it indicates if the compressor is actively cooling or if the set point is reached. Values are 'Idle', 'Heating', 'Cooling', 'FanOnly', 'PendingHeat', 'PendingCool', 'Vent'. 'temperature' is the current ambient temperature. 'heatsp' and 'coolsp' are the current heat/cool setpoints. The user indicates in their systems location preferences if they want english or metric, so just display the values as shown and do not worry about converting them. There are 4 mode buttons 'Off', 'Heat', 'Cool', and 'Auto' which should be bound to the 'mode' value, and when selected send the service &amp;quot;urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;quot; and action &amp;quot;SetModeTarget&amp;quot; with the argument &amp;quot;NewModeTarget&amp;quot; has the values &amp;quot;Off&amp;quot;, &amp;quot;HeatOn&amp;quot;, &amp;quot;CoolOn&amp;quot; or &amp;quot;AutoChangeOver&amp;quot;. Depending on the space on the user interface these can either be 4 buttons with the active mode button selected, or a drop-down that shows the active mode and let's the user change it. The fan is simply on or off, so just display a 'fan' button which is highlighted if the 'fan' variable is 1. Be sure it's separate from the 4 modes so it doesn't look like a 5th mode. If the user selects it, send the service &amp;quot;urn:upnp-org:serviceId:HVAC_FanOperatingMode1&amp;quot; and action &amp;quot;SetMode&amp;quot; with the argument &amp;quot;NewMode&amp;quot; has the values &amp;quot;Auto&amp;quot; for off or &amp;quot;ContinuousOn&amp;quot; for on. In other words, if the fan was off and the fan button is not highlighted, send the value &amp;quot;ContinuousOn&amp;quot; and if it was on, send the value &amp;quot;Auto&amp;quot; so it is a toggle. Display the values for 'heatsp' and 'coolsp', but if the user selects either one, display a drop-down or a pop-up or a keypad to let the user select a new temperature. Then send the service &amp;quot;urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&amp;quot; or &amp;quot;urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&amp;quot; with the action &amp;quot;SetCurrentSetpoint&amp;quot; and the argument &amp;quot;NewCurrentSetpoint&amp;quot; is whatever temperature the user choose. Display the value of the 'temperature' to the user as read only, since it's the ambient temperature. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #6 - Camera: These don't have a status. The control button is marked 'VIEW', but it doesn't send an action. It just displays an image viewer on the controller. The viewer should have a large JPEG image which you get by calling: http://ip:3480/data_request?id=cam_image&amp;amp;amp;Device_Num=x where x is the device ID. This request returns a JPEG file. If the camera also has a status 'streaming' and the status is not empty, the the image viewer popup should display a 'LIVE VIDEO' button, which displays the streaming video instead. See the [[Remote Camera Streaming]] to learn how. Both the JPEG image viewer and the motion image viewer must have buttons for the user to control the pan/tilt/zoom of the camera. These buttons are L, R, U, D, +, - (for left, right, up, down, zoom in, zoom out). When those buttons are pressed, use the lu_action with the service &amp;quot;urn:micasaverde-com:serviceId:PanTiltZoom1&amp;quot; and the action &amp;quot;MoveLeft&amp;quot;, &amp;quot;MoveRight&amp;quot;, &amp;quot;MoveUp&amp;quot;, &amp;quot;MoveDown&amp;quot;, &amp;quot;ZoomIn&amp;quot; or &amp;quot;ZoomOut&amp;quot;. There are no arguments for those actions. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #7 - Door lock: 'status' is 1 for locked or 0 for unlocked. Display a 'lock' and 'unlock' button which are bound to the 'status' variable. If selected, use the service &amp;quot;urn:micasaverde-com:serviceId:DoorLock1&amp;quot; action &amp;quot;SetTarget&amp;quot; and value newTargetValue which is 0 for unlocked and 1 for locked. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #8 - Window covering: same as Dimmable Light. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #16 - Humidity sensor: 'humidity' is the relative humidity from 0-100. Just display the 'humidity', there are no control buttons. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #17 - Temperature sensor: 'temperature' same as with a thermostat. Just display the 'temperature', there are no control buttons. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #18 - Light sensor: 'light' is a measurement of the ambient light in the room. There is no universal scale, so just display the number for the user. Just display the 'light', there are no control buttons. &lt;br /&gt;
&lt;br /&gt;
CATEGORY #21 - Power meter: 'watts' is the current consumption in watts. Just display the 'watts', there are no control buttons. &lt;br /&gt;
&lt;br /&gt;
Note: All devices, regardless of category, will have a 'watts' tag if we can measure the current consumption. &lt;br /&gt;
&lt;br /&gt;
== Testing everything on a public MiOS engine  ==&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;NOTE:&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;demo.mios.com it's not available anymore&amp;lt;/span&amp;gt;.''' &lt;br /&gt;
&lt;br /&gt;
A MiOS engine is available on the internet with a static IP so you can use it to test your user interface both in local mode, as well as remote mode. The IP is demo.mios.com (76.168.224.30). So to test your application in local mode, just use that IP and you will talk to it as though it were on the local network. The port 3480 is publicly accessible like a device on the local network would be (see: http://76.168.224.30:3480/data_request?id=lu_sdata). You can also test it in remote mode with the username demomios password demomios123 and serial number 12082. So, you can retrieve the same data above with this URL in remote mode: https://fwd2.mios.com/demomios/demomios123/12082/data_request?id=lu_sdata &lt;br /&gt;
&lt;br /&gt;
So, as a walkthrough to see how things work, first open up the regular MiOS web-based user interface that comes with the system at: http://demo.mios.com:8080/cmh/ Note that unlike the simple control-only user interface described in this document, this is a full user interface that let's you change configuration and do advanced things. It uses a different polling mechanism than the simple lu_sdata described here. &lt;br /&gt;
&lt;br /&gt;
Now, in another tab, using Firefox, which has a built-in xml parser, open: http://demo.mios.com:3480/data_request?id=lu_sdata&amp;amp;amp;output_format=xml NOTE: You will not use output_format=xml in your app, it's just to make it easier to see what's going if you have a Firefox browser. &lt;br /&gt;
&lt;br /&gt;
Now, in another tab, open this URL, but substitute the dataversion and loadtime variables from the prior tab: http://demo.mios.com:3480/data_request?id=lu_sdata&amp;amp;amp;output_format=xml&amp;amp;amp;loadtime=1282601808&amp;amp;amp;dataversion=601808034&amp;amp;amp;minimumdelay=3000 &lt;br /&gt;
&lt;br /&gt;
You should see that the page waits 3 seconds to load because the minimum delay is a minimum response time. Then you get an empty page without any data, and the tag full is 0. This means nothing has changed since the dataversion. If you change even 1 digit in the loadtime= on the URL, which is a timestamp of the configuration file, then you will get back the full data again because the lu_sdata requests sees that you do not have the current database. &lt;br /&gt;
&lt;br /&gt;
Now put back the correct loadtime and dataversion and add &amp;amp;amp;timeout=15 to the URL, like this: http://demo.mios.com:3480/data_request?id=lu_sdata&amp;amp;amp;output_format=xml&amp;amp;amp;loadtime=1282601808&amp;amp;amp;dataversion=601808034&amp;amp;amp;minimumdelay=3000&amp;amp;amp;timeout=15 &lt;br /&gt;
&lt;br /&gt;
You should see that it now waits 15 seconds, and again returns nothing. Now change the timeout to 60, and open the page again. During the next 60 seconds while the page is loading, go back to the MiOS user interface you first opened, and in the room &amp;quot;Patio&amp;quot; turn the 'White Light' on if it's off, or off it's on. The tab that's blocking on the lu_sdata should immediately return and give you this: &amp;amp;lt;device id=&amp;quot;3&amp;quot; status=&amp;quot;1&amp;quot; state=&amp;quot;1&amp;quot; comment=&amp;quot;White Light: Sending the Z-Wave command after 0 retries&amp;quot;/&amp;amp;gt; &lt;br /&gt;
&lt;br /&gt;
This is what causes your user interface to update device id 3. The state is now '1', meaning it's pending or busy while the engine is turning on or off the device. The indicator should appear in blue at this point. Copy/paste the dataversion from the request back into the URL and request it again. This time you should see: &amp;amp;lt;device id=&amp;quot;3&amp;quot; status=&amp;quot;0&amp;quot; state=&amp;quot;4&amp;quot; comment=&amp;quot;&amp;quot;/&amp;amp;gt; &lt;br /&gt;
&lt;br /&gt;
The state will be 4 if you do it soon, meaning your user interface should show the device with a green 'success' indicator, and if you do it again in 30 seconds, it will have a state of -1, meaning nothing. &lt;br /&gt;
&lt;br /&gt;
To turn the device like your user interface will, open this: &lt;br /&gt;
&lt;br /&gt;
http://demo.mios.com:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=3&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
change the =1 to an =0 to turn it off. Note that the response is a jobID. This means the engine is asynchronously turning on/off the device. &lt;br /&gt;
&lt;br /&gt;
Now try to turn on or off device #26, like this: &lt;br /&gt;
&lt;br /&gt;
http://demo.mios.com:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=26&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=0 &lt;br /&gt;
&lt;br /&gt;
You will get back an error &amp;quot;ERROR: No implementation&amp;quot;. In your user interface, this means if the user tries to control device #26, the user should get an error popup dialog box with that error message in it. &lt;br /&gt;
&lt;br /&gt;
You can test all the controls in your user interface with this demo system since it has all the current device categories. The devices in the room &amp;quot;Patio&amp;quot; are real devices and will give you proper responses when you try to control them. All other devices are dummy devices that will return an error if you do anything with them. The 'White Light' is a functioning light that should go through the pending and success states when you control it. The red light is a light that is ok, but, every time you try to control it, the job will fail. So the user should see a blue pending for a while when trying to turn it on or off, which then goes red and stays there for several seconds with an error message, but, after a while, reverts back to a neutral state (-1). The device 'Bad Light' is in a perpetually bad state and should always appear as red. &lt;br /&gt;
&lt;br /&gt;
In the patio the scenes 'Light on' and 'Light off' turn the white light on and off. One or the other scene will be 'active' depending on what state the light is in. &lt;br /&gt;
&lt;br /&gt;
Please don't try to change the configuration settings on this demo system since it is used by several developers. If something is messed up on it, email support [at] micasaverde [dot] com and someone will restore it back to the default setting. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Window_Covering_Notes</id>
		<title>Window Covering Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Window_Covering_Notes"/>
				<updated>2012-08-02T18:43:21Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;There are a few different ways in Z-Wave that window covering devices are controlled, and our experience is that implementation is not always universal among all devices.  In the...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There are a few different ways in Z-Wave that window covering devices are controlled, and our experience is that implementation is not always universal among all devices.&lt;br /&gt;
&lt;br /&gt;
In the UI, if a device supports COMMAND_CLASS_SWITCH_MULTILEVEL, the UP button sends SWITCH_MULTILEVEL_START_LEVEL_CHANGE with the arguments 0x60, 0x0, and the DOWN button uses arguments 0x20, 0x0, while stop does SWITCH_MULTILEVEL_STOP_LEVEL_CHANGE.&lt;br /&gt;
&lt;br /&gt;
If the device does not support that command class, but does support COMMAND_CLASS_BASIC_WINDOW_COVERING, the UP button sends BASIC_WINDOW_COVERING_START_LEVEL_CHANGE with the argument 0x0, DOWN sends 64, and STOP sends BASIC_WINDOW_COVERING_STOP_LEVEL_CHANGE.&lt;br /&gt;
&lt;br /&gt;
If the device supports neither, then Up sends a BASIC_SET with 0x63, Down sends a BASIC_SET with 0x0.&lt;br /&gt;
&lt;br /&gt;
If you set the variable urn:micasaverde-com:serviceId:HaDevice1 : ReverseOnOff to &amp;quot;1&amp;quot;, then Down will be sent as Up, and Up as Down.&lt;br /&gt;
&lt;br /&gt;
The Close and Open buttons as well as the slider send commands the same way they are sent to a light switch, namely with SWITCH_MULTILEVEL or a BASIC_SET.&lt;br /&gt;
&lt;br /&gt;
Thus between all the close/open, up/down/stop all common variants are supported and one of them should achieve the desired result on your window covering.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/AlternateEventServer</id>
		<title>AlternateEventServer</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/AlternateEventServer"/>
				<updated>2012-07-12T03:42:13Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vera calls Mios's event servers to report events, like sensor tripped, triggers, etc. Mios's event servers send out text messages and emails to report these events. &lt;br /&gt;
&lt;br /&gt;
Some very advanced users have asked to setup their own event server that Vera will call to report events. If you add your own, alternate event server, Vera will still send events to Mios's event server unchanged, however Vera will also post the same event to the alternate server of your choice. &lt;br /&gt;
&lt;br /&gt;
Vera will send the event as a standard HTTPS (secure) GET to &amp;lt;tt&amp;gt;yourserver/alert&amp;lt;/tt&amp;gt; with the arguments passed on the URL, like this (assuming your server is &amp;lt;tt&amp;gt;myserver.me.com&amp;lt;/tt&amp;gt;): &lt;br /&gt;
&lt;br /&gt;
  https://myserver.me.com/alert?&lt;br /&gt;
 PK_AccessPoint=[serial number of Vera; in Lua you can get it with [http://wiki.micasaverde.com/index.php/Luup_Lua_extensions#variable:_pk_accesspoint luup.pk_accesspoint]]&lt;br /&gt;
 &amp;amp;amp;HW_Key=[hardware key of Vera; in Lua you can get it with [http://wiki.micasaverde.com/index.php/Luup_Lua_extensions#variable:_hw_key luup.hw_key]]&lt;br /&gt;
 &amp;amp;amp;DeviceID=[device id that is associated with the alert]&lt;br /&gt;
 &amp;amp;amp;LocalDate=[the time the alert happened as human readable text]&lt;br /&gt;
 &amp;amp;amp;LocalTimestamp=[the time the alert happened as a unix timestamp in UTC]&lt;br /&gt;
 &amp;amp;amp;AlertType=[one of the alert types below]]&lt;br /&gt;
 &amp;amp;amp;SourceType=[one of the source types below]&lt;br /&gt;
 &amp;amp;amp;Argument=[an optional argument depending on the alert type]&lt;br /&gt;
 &amp;amp;amp;Format=[a file format, not normally used]&lt;br /&gt;
 &amp;amp;amp;Code=[a code for the alert, usually the variable that changed]&lt;br /&gt;
 &amp;amp;amp;Value=[the value corresponding to the code above]&lt;br /&gt;
 &amp;amp;amp;Description=[a human readable description of the event, or comments regarding it]&lt;br /&gt;
 &amp;amp;amp;Users=[a comma separated list of user id's that should be notified of the event]&lt;br /&gt;
&lt;br /&gt;
The page on your event server must respond with a plain text response containing PK_Alert:x where x is some number to identify the alert recorded on the server.  It can be any number, and just PK_Alert:0 if you don't assign a number to the alert.  Whatever it is will be put in Vera's logs along with the alert for cross reference.&lt;br /&gt;
&lt;br /&gt;
To use this alternate event logging set the top level user_data tag &amp;quot;AltEventServer&amp;quot; to the domain of your server. If your server is &amp;lt;tt&amp;gt;myserver.me.com&amp;lt;/tt&amp;gt;, do this by changing the 'ip' to be the IP of Vera, and opening this URL: &lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;amp;Variable=AltEventServer&amp;amp;amp;Value=myserver.me.com &lt;br /&gt;
&lt;br /&gt;
Then click ''Reload'' in Vera's UI to reload the engine with the changes. You can watch Vera send the data by logging into Vera's console as explained in [[Logon Vera SSH]] and then typing: &lt;br /&gt;
&lt;br /&gt;
tail -f /var/log/cmh/LuaUPnP.log | grep 'RAServerSync::SendAlert' &lt;br /&gt;
&lt;br /&gt;
To stop logging to your own server, call the &amp;lt;tt&amp;gt;variableset&amp;lt;/tt&amp;gt; again but leave the Value empty. &lt;br /&gt;
&lt;br /&gt;
==== Alert Types ====&lt;br /&gt;
&lt;br /&gt;
*  '''1''': ALERT_IMAGE&lt;br /&gt;
*  '''2''': ALERT_VIDEO&lt;br /&gt;
*  '''3''': ALERT_TRIGGER&lt;br /&gt;
*  '''4''': ALERT_VARIABLE&lt;br /&gt;
*  '''5''': ALERT_LOGON&lt;br /&gt;
*  '''6''': ALERT_GATEWAY_CONNECTED (Sent if the external IP changes or if it's been more than 24 hours since the last report.)&lt;br /&gt;
*  '''7''': ALERT_SYS_ERROR&lt;br /&gt;
*  '''8''': ALERT_VALIDATE_EMAIL&lt;br /&gt;
*  '''9''': ALERT_VALIDATE_SMS&lt;br /&gt;
* '''10''': ALERT_SYS_MESSAGE&lt;br /&gt;
&lt;br /&gt;
==== Source Types ====&lt;br /&gt;
&lt;br /&gt;
* '''1''': SOURCE_USER&lt;br /&gt;
* '''2''': SOURCE_TIMER&lt;br /&gt;
* '''3''': SOURCE_TRIGGER&lt;br /&gt;
* '''4''': SOURCE_VARIABLE&lt;br /&gt;
&lt;br /&gt;
==== File Formats ====&lt;br /&gt;
&lt;br /&gt;
* '''1''': FORMAT_JPEG&lt;br /&gt;
* '''2''': FORMAT_MJPEG&lt;br /&gt;
* '''3''': FORMAT_MP4&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Remotec_IRBlaster</id>
		<title>Remotec IRBlaster</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Remotec_IRBlaster"/>
				<updated>2012-06-20T14:36:45Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Remotec IRBlasters are supported in firmware versions 1.5.346 and higher.  Vera does not support the learning function of the Remotec.&lt;br /&gt;
&lt;br /&gt;
1.  If you haven't already included them in your network, go to Device, Add Devices, Add Z-Wave devices, and include the Remotec like any other Z-Wave device.  The 'z-wave include' button is marked PROG on the side of the 6-port blaster, and it's the big black round button on the top of the single port blaster.  NOTE: The Remotec will not include or exclude unless it is set to 'channel 1'.  If you have problems, tap the Prog button and confirm the LED blinks one time.  If not, see the manual to put it to channel 1.&lt;br /&gt;
&lt;br /&gt;
2.  After it is included, go to Devices, Add Device, and choose Add IR Device.&lt;br /&gt;
&lt;br /&gt;
3.  Choose the IR Blaster from the 'use transmitter' pull-down.  If you have a 6-port blaster, you will see the blaster + 6 ports.  NOTE: In firmware 1.5.346 you should choose the blaster itself, not one of the 6 ports.&lt;br /&gt;
&lt;br /&gt;
4.  Choose 'Manual setup' because the Remotec blasters have their own codesets.&lt;br /&gt;
&lt;br /&gt;
5.  You will then need to enter the codeset number.  Do not enter the 0 in front of a codeset.  If the manual says 0251, use 251.  If you have multiple codesets, or are not sure which one is best, you can enter several codesets separated with a comma.  For example, if you have a Samsung TV, you'll see there are 6 possible codesets.  If you don't know which one to use, enter them all like this: 251,261,351,1191,1311,1911&lt;br /&gt;
&lt;br /&gt;
6.  After you click 'Create Device', your new device will appear on the Devices, A/V Gear. Choose the 'control' button to bring up the remote control to test your new device.&lt;br /&gt;
&lt;br /&gt;
7.  If you entered multiple codesets, and the remote isn't working, there's a button in the upper right corner of the remote to toggle through all the codesets.  It will say #1 at first, meaning, we'll be using the first codeset you entered.  Click it to try the second codeset, third, etc., until you've tried them all and it comes back to #1.  Try each one until you find the one that works best.  It will continue to use whatever is the last codeset you selected, so you only need to do this once.  If you only entered one codeset, this button will not be there.&lt;br /&gt;
&lt;br /&gt;
NOTE: Due to a bug in 1.5.346, it won't automatically program the remotec with the codeset you entered until you hit the button described in step 7.  So if you add a device with only 1 codeset it won't work.  A temporary workaround is that if you you must enter at least 2 codesets.  If the codeset is 251, then enter codesets 1,251 in step #5.  This way you can hit the #1 button in step 7 to cycle to the 2nd codeset, and it will program the Remotec to use codeset #251.  This bug only affects release 1.5.346.&lt;br /&gt;
&lt;br /&gt;
Note that once you have confirmed the device is working, you can include this A/V device in scenes.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Source_Code</id>
		<title>Source Code</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Source_Code"/>
				<updated>2012-06-09T16:49:21Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
[[Category:Obsolete]]&lt;br /&gt;
----&lt;br /&gt;
'''This page is WIP'''&lt;br /&gt;
----&lt;br /&gt;
Vera is based on OpenWRT. The full source tree for OpenWRT is available at openwrt.org.&lt;br /&gt;
&lt;br /&gt;
We're using the following revisions :&lt;br /&gt;
&lt;br /&gt;
Vera1 : 11404 (https://svn.openwrt.org/openwrt/trunk)&lt;br /&gt;
&lt;br /&gt;
Vera2 : 21644 (svn://svn.openwrt.org/openwrt/branches/backfire)&lt;br /&gt;
&lt;br /&gt;
The busybox we use is the stock one distributed with openWRT.&lt;br /&gt;
&lt;br /&gt;
The only modification to GPL code is dnsmasq.  Our modified version is here: [[File:dnsmasq.zip]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Source_Code</id>
		<title>Source Code</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Source_Code"/>
				<updated>2012-06-09T16:40:36Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
[[Category:Obsolete]]&lt;br /&gt;
----&lt;br /&gt;
'''This page is WIP'''&lt;br /&gt;
----&lt;br /&gt;
Vera is based on OpenWRT. The full source tree for OpenWRT is available at openwrt.org.&lt;br /&gt;
&lt;br /&gt;
We're using the following revisions :&lt;br /&gt;
&lt;br /&gt;
Vera1 : 11404 (https://svn.openwrt.org/openwrt/trunk)&lt;br /&gt;
&lt;br /&gt;
Vera2 : 21644 (svn://svn.openwrt.org/openwrt/branches/backfire)&lt;br /&gt;
&lt;br /&gt;
The busybox we use is the stock one distributed with openWRT.&lt;br /&gt;
&lt;br /&gt;
[[File:dnsmasq.zip]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:Dnsmasq.zip</id>
		<title>File:Dnsmasq.zip</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:Dnsmasq.zip"/>
				<updated>2012-06-09T16:39:35Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Source_Code</id>
		<title>Source Code</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Source_Code"/>
				<updated>2012-06-08T00:57:21Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
[[Category:Obsolete]]&lt;br /&gt;
----&lt;br /&gt;
'''This page is WIP'''&lt;br /&gt;
----&lt;br /&gt;
Vera is based on OpenWRT. The full source tree for OpenWRT is available at openwrt.org.&lt;br /&gt;
&lt;br /&gt;
We're using the following revisions :&lt;br /&gt;
&lt;br /&gt;
Vera1 : 11404 (https://svn.openwrt.org/openwrt/trunk)&lt;br /&gt;
&lt;br /&gt;
Vera2 : 21644 (svn://svn.openwrt.org/openwrt/branches/backfire)&lt;br /&gt;
&lt;br /&gt;
The busybox we use is the stock one distributed with openWRT.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2012-05-19T21:45:51Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* function: attr_set */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP addess and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. &amp;quot;v2&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, &amp;lt;tt&amp;gt;is_ready&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;tt&amp;gt;&amp;lt;incoming&amp;gt; block&amp;lt;/tt&amp;gt; that only processes data if &amp;lt;tt&amp;gt;is_ready(lul_device)&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; parameter, if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device, which, if it's a string, is interpreted as a udn, and if it's a number, is the device number. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), device (string or number), [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP service+variable will be set to value for device, which if it's a string, is interpreted as a udn, and if it's a number, as a device id. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: value (string), time (number) &lt;br /&gt;
&lt;br /&gt;
If the service+variable or device does not exist, it returns nothing. Otherwise it returns the value of the UPnP service+variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). You can assign just the value to a variable, as follows:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc.&lt;br /&gt;
&lt;br /&gt;
=== function: attr_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: string or none&lt;br /&gt;
&lt;br /&gt;
Gets the top level attribute for the device.  Examples of attributes are 'mac', 'name', 'id', etc.  If the attribute doesn't exist, it returns nothing.  If nothing is passed in for device, it gets the top level attribute from the master userdata, like firmware_version.&lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the WAP mobile phone plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    return lul_html&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
'''parameters''': service ID (string), device (string or number)&lt;br /&gt;
&lt;br /&gt;
'''returns''': ''true'' if the device supports the service, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
A device supports a service if there is at least a command or state variable defined for that device using that service. Setting UPnP variables is unrestricted and free form, and the engine doesn't really know if a device actually uses it or does anything with it. So this function isn't really definitive.&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (boolean), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to true if the device is failing. If device is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: boolean &lt;br /&gt;
&lt;br /&gt;
Returns true if it's past sunset and before sunrise. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
'''Warning:''' luup.sleep doesn't work reliably: http://bugs.micasaverde.com/view.php?id=1480&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
'''parameters:''' none&lt;br /&gt;
&lt;br /&gt;
'''returns:''' The next sunset / sunrise in a Unix timestamp (i.e. the number of seconds since 1/1/1970 in UTC time). You can do a diff with &amp;lt;tt&amp;gt;os.time&amp;lt;/tt&amp;gt; to see how long it will be for the next event.  &amp;lt;tt&amp;gt;luup.sunset-os.time&amp;lt;/tt&amp;gt; is the number of seconds before the next sunset. Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
'''Firmware required:''' 1.5.353&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), id (string), description (string), device_type (string), device_filename (string), implementation_filename (string), parameters (string), embedded (boolean) [, invisible (boolean)]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt;. If &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
Pass in the &amp;lt;tt&amp;gt;ptr&amp;lt;/tt&amp;gt; which you received from the &amp;lt;tt&amp;gt;luup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt; which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as &amp;lt;tt&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the&amp;amp;nbsp;XML file with the UPnP device specification. The deviceType from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually. If the device_file contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the 'embedded' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; to separate service, variable and value, like this: &amp;lt;tt&amp;gt;service,variable=value\nservice&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If device is a string it is interpreted as a udn, if it's a number, as a device id. Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ip (string) port (number), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port. &lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean) &lt;br /&gt;
&lt;br /&gt;
In Lua a string can contain binary data, so data may be a binary block. If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nill if an error occurred. &lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/IRFID</id>
		<title>IRFID</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/IRFID"/>
				<updated>2012-05-19T19:30:41Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;Remove the back cover from the iRFID and be sure the AA batteries are inserted.  Put Vera into 'add device' mode either by pressing the Add button on Vera, or by choosing Devices...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Remove the back cover from the iRFID and be sure the AA batteries are inserted.  Put Vera into 'add device' mode either by pressing the Add button on Vera, or by choosing Devices, Add Devices, Add Z-Wave devices.  Active the iRFID inclusion by holding the tamper switch on the back of the iRFID for 1 second and releasing.  Wait a minute for it to appear on Vera's dashboard.  If Vera says 'Waiting for device to wakeup', hold the tamper swtich for 1 second again until Vera successfully configures the nodes.&lt;br /&gt;
&lt;br /&gt;
The RFID tags all have a code number.  Touch the 'home' button and immediately scan the RFID tag.  In Vera's UI, the code number will be shown in the info panel at the top.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Requests</id>
		<title>Luup Requests</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Requests"/>
				<updated>2012-05-08T23:18:29Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* finddevice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
In addition to sending requests using standard UPnP, you can also do most things using a simple HTTP requests.  Use the built-in URL &amp;lt;tt&amp;gt;data_request&amp;lt;/tt&amp;gt;, and pass the following on the URL:&lt;br /&gt;
*&amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; the id of the request (prior to 15 Oct 2010 all requests had an lu_ in front, which is now optional), &lt;br /&gt;
*&amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; the format in which you want a response as &amp;lt;tt&amp;gt;json&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;xml&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;text&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Not all requests support all &amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; options.  Here is a list of requests:&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=user_data&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
This returns the configuration data for Vera, which is a list of all devices and the UPnP variables which are persisted between resets as well as rooms, names, and other data the user sets as part of the configuration.&lt;br /&gt;
&lt;br /&gt;
==status==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
Or for a specific device: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;UDN=uuid:4d494342-5342-5645-0002-000000000002 or http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;DeviceNum=6&lt;br /&gt;
&lt;br /&gt;
This returns the current status for all devices including all the current upnp variables and the status of any active jobs.&lt;br /&gt;
&lt;br /&gt;
==sdata==&lt;br /&gt;
&lt;br /&gt;
This is an abbreviated form of user_data and status (sdata=summary data).  It allows a user interface that is only worried about control, and not detailed configuration, to get a summary of the data that would normally be presented to the user and to monitor the changes.  See [[UI_Simple]] for a walkthrough.&lt;br /&gt;
&lt;br /&gt;
==actions==&lt;br /&gt;
&lt;br /&gt;
==device==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=3&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=delete&amp;amp;device=5&lt;br /&gt;
&lt;br /&gt;
This renames or deletes a device.  Use action=rename or action=delete.  For rename, you can optionally assign a room by either passing either the ID or the name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---old---&lt;br /&gt;
This returns all the XML with all the UPNP device description documents.  Use: http://ipaddress:3480/data_request?id=device&amp;amp;output_format=xml&amp;amp;DeviceNum=x or &amp;amp;UDN=y to narrow it down.  Then when you see the service URL's, like &amp;lt;SCPDURL&amp;gt;/luvd/S_HVAC_UserOperatingMode1.xml&amp;lt;/SCPDURL&amp;gt;, you can view them with: http://ipaddress:3480/luvd/S_HVAC_UserOperatingMode1.xml&lt;br /&gt;
---end old---&lt;br /&gt;
&lt;br /&gt;
==scene==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=record  &lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=pause&amp;amp;seconds=y&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=stoprecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=listrecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=deleterecord&amp;amp;number=x&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=saverecord&amp;amp;name=whatever&amp;amp;room=X&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=rename&amp;amp;scene=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=create&amp;amp;json=[valid json data]&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=list&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a scene depending on the action.&lt;br /&gt;
&lt;br /&gt;
Recording a scene means whatever actions come in after sending the 'record' will be saved into an internal buffer.  listrecord shows what's recorded so far.  pause adds a pause.  deleterecord deletes some action in the internal buffer.  When deleting, for number=x, use the same 'id' in listrecord.  saverecord takes the internal buffer, the recorded macro, and saves it as an actual scene.&lt;br /&gt;
&lt;br /&gt;
To create a scene by hand, rather than recording it, use 'create'.  When using the 'create' command json must be valid JSON for a scene as documented in [[Scene_Syntax]].  The name, room and optional id (if you're overwriting an existing scene) are passed in the json, so nothing is on the command line except the json.  Because the json data can be long it is recommended to send it as an http POST instead of GET with the data passed with the name &amp;quot;json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
list returns the JSON data for an existing scene.&lt;br /&gt;
&lt;br /&gt;
==room==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=create&amp;amp;name=Kitchen&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=rename&amp;amp;room=5&amp;amp;name=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;room=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a room depending on the action.  To rename or delete a room you must pass the room id for the room=.&lt;br /&gt;
&lt;br /&gt;
==file==&lt;br /&gt;
&lt;br /&gt;
==lua==&lt;br /&gt;
&lt;br /&gt;
== action  ==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=6&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
Sends a UPnP action. &lt;br /&gt;
&lt;br /&gt;
To run a scene, you send the action 'RunScene' like this:: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=&amp;amp;lt;SceneNum&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
==variableset==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this sets a top-level json tag called &amp;quot;Variable&amp;quot; with the value.&lt;br /&gt;
&lt;br /&gt;
==variableget==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableget&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this gets a top-level json tag called &amp;quot;Variable&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==reload==&lt;br /&gt;
&lt;br /&gt;
Resets the Luup engine with any new configuration settings.&lt;br /&gt;
&lt;br /&gt;
==alive==&lt;br /&gt;
&lt;br /&gt;
Return OK if the engine is running.&lt;br /&gt;
&lt;br /&gt;
==finddevice==&lt;br /&gt;
&lt;br /&gt;
Returns the '''device number''', '''UDN''' and '''device type''' of the first device that matches any or all the parameters passed on the URL: &amp;lt;tt&amp;gt;devtype&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ip&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;devid&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;devid&amp;lt;/tt&amp;gt; is the ''altid'' of the device.  Or instead of devid, pass &amp;lt;tt&amp;gt;devnum&amp;lt;/tt&amp;gt; and it will find the device with that id (device number).&lt;br /&gt;
&lt;br /&gt;
Example: http://192.168.81.1:3480/data_request?id=finddevice&amp;amp;devid=6&lt;br /&gt;
&lt;br /&gt;
==resync==&lt;br /&gt;
&lt;br /&gt;
ReSync's all the devices, rooms, users, sections with event servers and returns OK&lt;br /&gt;
&lt;br /&gt;
==wget==&lt;br /&gt;
&lt;br /&gt;
Returns the contents of the URL you pass in the &amp;quot;url&amp;quot; argument.  Optionally append &amp;quot;user&amp;quot; and &amp;quot;pass&amp;quot; arguments for http authentication, and &amp;quot;timeout&amp;quot; to specify the maximum time to wait in seconds.&lt;br /&gt;
&lt;br /&gt;
==iprequests==&lt;br /&gt;
&lt;br /&gt;
Returns the recent IP requests in order by most recent first, including information about devices in use and if the IP is blacklisted (ignored by the plug and play mechanism).  Optionally append &amp;quot;oldest&amp;quot; to specify the oldest IP request in seconds.&lt;br /&gt;
&lt;br /&gt;
==blacklistip==&lt;br /&gt;
&lt;br /&gt;
Append &amp;quot;ip&amp;quot; to the URL, and optionally &amp;quot;remove=1&amp;quot; to add (or remove) the IP to the blacklist so plug and play IP devices won't be added.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;Not implemented yet!&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==live_energy_usage==&lt;br /&gt;
&lt;br /&gt;
For backward compatibility, it reports the current energy usage in a tab delimited format.&lt;br /&gt;
&lt;br /&gt;
Example: http://192.168.81.1:3480/data_request?id=live_energy_usage&lt;br /&gt;
&lt;br /&gt;
 '''Device #'''    '''Name'''              '''Room'''         '''Category'''    '''Watts'''&lt;br /&gt;
 59          Basement Light    Basement     3           20&lt;br /&gt;
 60          Bedroom Light     1st Floor    3           0&lt;br /&gt;
 61          Porch Light       Outside      3           30&lt;br /&gt;
&lt;br /&gt;
== request_image ==&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;NOTE:&amp;lt;/span&amp;gt;'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt; request_video is not implemented yet.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns an image from a camera. This fetches the image from the camera using the URL variable for the device. Pass arguments: &lt;br /&gt;
&lt;br /&gt;
 cam = the device id of the camera.  This is the only mandatory argument.&lt;br /&gt;
 res = optional: a resolution, which gets appended to the variable.  So passing &amp;quot;low&amp;quot; means the image from the URL_low variable will be returned.  If it doesn't exist it reverts to the standard URL or DirectStreamingURL &lt;br /&gt;
 timeout = optional: how long to wait for the image to be retrieved, or how long to retrieve video.  defaults to 10 seconds.&lt;br /&gt;
 url = optional: override the camera's default URL&lt;br /&gt;
 ip = optional: override the camera's default ip&lt;br /&gt;
 user or pass = optional: override the camera's default username/password&lt;br /&gt;
&lt;br /&gt;
==jobstatus==&lt;br /&gt;
&lt;br /&gt;
Returns the status of a job. The parameters are &amp;lt;tt&amp;gt;job&amp;lt;/tt&amp;gt;, which is the job ID and optionally &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt;, which is the plugin name. For a Z-Wave job the &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; parameter '''must''' be ''zwave''.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;job&amp;lt;/tt&amp;gt; is invalid the status returned is ''-1''.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
* '''0''': Job waiting to start.&lt;br /&gt;
* '''1''': Job in progress.&lt;br /&gt;
* '''2''': Job error.&lt;br /&gt;
* '''3''': Job aborted.&lt;br /&gt;
* '''4''': Job done.&lt;br /&gt;
* '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
* '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
* '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now. &lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
http://192.168.81.1:3480/data_request?id=jobstatus&amp;amp;job=13&lt;br /&gt;
&lt;br /&gt;
http://192.168.81.1:3480/data_request?id=jobstatus&amp;amp;job=6&amp;amp;plugin=zwave&lt;br /&gt;
&lt;br /&gt;
==invoke==&lt;br /&gt;
&lt;br /&gt;
==relay==&lt;br /&gt;
&lt;br /&gt;
This tells the system to setup a relay so that you can access a device on the home network from outside the home.  This is most commonly used to fetch streaming video from a camera, although it can actually be used for any IP device.  This takes either an 'ip' or 'device' argument.  If you pass a device, this is assumed to be a device ID, and the system will find the ip associated with that device.  Optionally pass a port argument for the port you want to be relayed.  Port 80 is assumed if none is specified.&lt;br /&gt;
&lt;br /&gt;
This request will return a 'server:port' which you can use externally to access the designated device.  The relay stays open for 15 minutes before closing, at which point you will need to open it again.&lt;br /&gt;
&lt;br /&gt;
So, assume you have a NAS device on the home network with the ip 192.168.1.55 and the NAS runs a configuration web page on port 80.  You could access it by doing this:&lt;br /&gt;
&lt;br /&gt;
data_request?ip=192.168.1.55&amp;amp;port=80&lt;br /&gt;
&lt;br /&gt;
and if the response is: &amp;quot;someserver:20202&amp;quot;, then for 15 minutes, &amp;quot;http://someserver:20202&amp;quot; will be the NAS's configuration page.&lt;br /&gt;
&lt;br /&gt;
If you want to access a camera, device #5, then do this:&lt;br /&gt;
&lt;br /&gt;
data_request?device=5&lt;br /&gt;
&lt;br /&gt;
and if the response is &amp;quot;someserver:20211&amp;quot; and if the 'DirectStreamURL' variable (or 'streaming' in sdata) is &amp;quot;video.mpeg&amp;quot;, then for 15 minutes you can access the camera's video at: http://someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
Note that if the device, the camera in this case, has http authentication, you will need to pass this too.  So, if the user_data or sdata for the camera shows the user name is 'johndoe' and the password is 'john123', then you can view the video at: http://john:john123@someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: For the 15 minutes while this relay is open, it will be open to anyone on the internet and public.  Therefore, for security, you may want to add to the data_request the argument externalip=x where x is the routable, external IP, such as 70.182.172.111, of the device that will be accessing the port.  This means that when the relay is open, a firewall will be set on the relay server so that incoming connections are only accepted from that ip address.&lt;br /&gt;
&lt;br /&gt;
==What to do when the HTTP request string is too long==&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php/topic,10170.msg69530.html#msg69530&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Requests</id>
		<title>Luup Requests</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Requests"/>
				<updated>2012-05-08T23:16:52Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* finddevice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
In addition to sending requests using standard UPnP, you can also do most things using a simple HTTP requests.  Use the built-in URL &amp;lt;tt&amp;gt;data_request&amp;lt;/tt&amp;gt;, and pass the following on the URL:&lt;br /&gt;
*&amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; the id of the request (prior to 15 Oct 2010 all requests had an lu_ in front, which is now optional), &lt;br /&gt;
*&amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; the format in which you want a response as &amp;lt;tt&amp;gt;json&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;xml&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;text&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Not all requests support all &amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; options.  Here is a list of requests:&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=user_data&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
This returns the configuration data for Vera, which is a list of all devices and the UPnP variables which are persisted between resets as well as rooms, names, and other data the user sets as part of the configuration.&lt;br /&gt;
&lt;br /&gt;
==status==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
Or for a specific device: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;UDN=uuid:4d494342-5342-5645-0002-000000000002 or http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;DeviceNum=6&lt;br /&gt;
&lt;br /&gt;
This returns the current status for all devices including all the current upnp variables and the status of any active jobs.&lt;br /&gt;
&lt;br /&gt;
==sdata==&lt;br /&gt;
&lt;br /&gt;
This is an abbreviated form of user_data and status (sdata=summary data).  It allows a user interface that is only worried about control, and not detailed configuration, to get a summary of the data that would normally be presented to the user and to monitor the changes.  See [[UI_Simple]] for a walkthrough.&lt;br /&gt;
&lt;br /&gt;
==actions==&lt;br /&gt;
&lt;br /&gt;
==device==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=3&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=delete&amp;amp;device=5&lt;br /&gt;
&lt;br /&gt;
This renames or deletes a device.  Use action=rename or action=delete.  For rename, you can optionally assign a room by either passing either the ID or the name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---old---&lt;br /&gt;
This returns all the XML with all the UPNP device description documents.  Use: http://ipaddress:3480/data_request?id=device&amp;amp;output_format=xml&amp;amp;DeviceNum=x or &amp;amp;UDN=y to narrow it down.  Then when you see the service URL's, like &amp;lt;SCPDURL&amp;gt;/luvd/S_HVAC_UserOperatingMode1.xml&amp;lt;/SCPDURL&amp;gt;, you can view them with: http://ipaddress:3480/luvd/S_HVAC_UserOperatingMode1.xml&lt;br /&gt;
---end old---&lt;br /&gt;
&lt;br /&gt;
==scene==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=record  &lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=pause&amp;amp;seconds=y&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=stoprecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=listrecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=deleterecord&amp;amp;number=x&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=saverecord&amp;amp;name=whatever&amp;amp;room=X&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=rename&amp;amp;scene=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=create&amp;amp;json=[valid json data]&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=list&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a scene depending on the action.&lt;br /&gt;
&lt;br /&gt;
Recording a scene means whatever actions come in after sending the 'record' will be saved into an internal buffer.  listrecord shows what's recorded so far.  pause adds a pause.  deleterecord deletes some action in the internal buffer.  When deleting, for number=x, use the same 'id' in listrecord.  saverecord takes the internal buffer, the recorded macro, and saves it as an actual scene.&lt;br /&gt;
&lt;br /&gt;
To create a scene by hand, rather than recording it, use 'create'.  When using the 'create' command json must be valid JSON for a scene as documented in [[Scene_Syntax]].  The name, room and optional id (if you're overwriting an existing scene) are passed in the json, so nothing is on the command line except the json.  Because the json data can be long it is recommended to send it as an http POST instead of GET with the data passed with the name &amp;quot;json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
list returns the JSON data for an existing scene.&lt;br /&gt;
&lt;br /&gt;
==room==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=create&amp;amp;name=Kitchen&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=rename&amp;amp;room=5&amp;amp;name=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;room=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a room depending on the action.  To rename or delete a room you must pass the room id for the room=.&lt;br /&gt;
&lt;br /&gt;
==file==&lt;br /&gt;
&lt;br /&gt;
==lua==&lt;br /&gt;
&lt;br /&gt;
== action  ==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=6&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
Sends a UPnP action. &lt;br /&gt;
&lt;br /&gt;
To run a scene, you send the action 'RunScene' like this:: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=&amp;amp;lt;SceneNum&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
==variableset==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this sets a top-level json tag called &amp;quot;Variable&amp;quot; with the value.&lt;br /&gt;
&lt;br /&gt;
==variableget==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableget&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this gets a top-level json tag called &amp;quot;Variable&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==reload==&lt;br /&gt;
&lt;br /&gt;
Resets the Luup engine with any new configuration settings.&lt;br /&gt;
&lt;br /&gt;
==alive==&lt;br /&gt;
&lt;br /&gt;
Return OK if the engine is running.&lt;br /&gt;
&lt;br /&gt;
==finddevice==&lt;br /&gt;
&lt;br /&gt;
Returns the '''device number''', '''UDN''' and '''device type''' of the first device that matches any or all the parameters passed on the URL: &amp;lt;tt&amp;gt;devtype&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ip&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;devid&amp;lt;/tt&amp;gt;, where &amp;lt;tt&amp;gt;devid&amp;lt;/tt&amp;gt; is the ''altid'' of the device.  Or instead of devid, pass &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; and it will find the device with that id (device number).&lt;br /&gt;
&lt;br /&gt;
Example: http://192.168.81.1:3480/data_request?id=finddevice&amp;amp;devid=6&lt;br /&gt;
&lt;br /&gt;
==resync==&lt;br /&gt;
&lt;br /&gt;
ReSync's all the devices, rooms, users, sections with event servers and returns OK&lt;br /&gt;
&lt;br /&gt;
==wget==&lt;br /&gt;
&lt;br /&gt;
Returns the contents of the URL you pass in the &amp;quot;url&amp;quot; argument.  Optionally append &amp;quot;user&amp;quot; and &amp;quot;pass&amp;quot; arguments for http authentication, and &amp;quot;timeout&amp;quot; to specify the maximum time to wait in seconds.&lt;br /&gt;
&lt;br /&gt;
==iprequests==&lt;br /&gt;
&lt;br /&gt;
Returns the recent IP requests in order by most recent first, including information about devices in use and if the IP is blacklisted (ignored by the plug and play mechanism).  Optionally append &amp;quot;oldest&amp;quot; to specify the oldest IP request in seconds.&lt;br /&gt;
&lt;br /&gt;
==blacklistip==&lt;br /&gt;
&lt;br /&gt;
Append &amp;quot;ip&amp;quot; to the URL, and optionally &amp;quot;remove=1&amp;quot; to add (or remove) the IP to the blacklist so plug and play IP devices won't be added.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;Not implemented yet!&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==live_energy_usage==&lt;br /&gt;
&lt;br /&gt;
For backward compatibility, it reports the current energy usage in a tab delimited format.&lt;br /&gt;
&lt;br /&gt;
Example: http://192.168.81.1:3480/data_request?id=live_energy_usage&lt;br /&gt;
&lt;br /&gt;
 '''Device #'''    '''Name'''              '''Room'''         '''Category'''    '''Watts'''&lt;br /&gt;
 59          Basement Light    Basement     3           20&lt;br /&gt;
 60          Bedroom Light     1st Floor    3           0&lt;br /&gt;
 61          Porch Light       Outside      3           30&lt;br /&gt;
&lt;br /&gt;
== request_image ==&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;NOTE:&amp;lt;/span&amp;gt;'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt; request_video is not implemented yet.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns an image from a camera. This fetches the image from the camera using the URL variable for the device. Pass arguments: &lt;br /&gt;
&lt;br /&gt;
 cam = the device id of the camera.  This is the only mandatory argument.&lt;br /&gt;
 res = optional: a resolution, which gets appended to the variable.  So passing &amp;quot;low&amp;quot; means the image from the URL_low variable will be returned.  If it doesn't exist it reverts to the standard URL or DirectStreamingURL &lt;br /&gt;
 timeout = optional: how long to wait for the image to be retrieved, or how long to retrieve video.  defaults to 10 seconds.&lt;br /&gt;
 url = optional: override the camera's default URL&lt;br /&gt;
 ip = optional: override the camera's default ip&lt;br /&gt;
 user or pass = optional: override the camera's default username/password&lt;br /&gt;
&lt;br /&gt;
==jobstatus==&lt;br /&gt;
&lt;br /&gt;
Returns the status of a job. The parameters are &amp;lt;tt&amp;gt;job&amp;lt;/tt&amp;gt;, which is the job ID and optionally &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt;, which is the plugin name. For a Z-Wave job the &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; parameter '''must''' be ''zwave''.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;job&amp;lt;/tt&amp;gt; is invalid the status returned is ''-1''.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
* '''0''': Job waiting to start.&lt;br /&gt;
* '''1''': Job in progress.&lt;br /&gt;
* '''2''': Job error.&lt;br /&gt;
* '''3''': Job aborted.&lt;br /&gt;
* '''4''': Job done.&lt;br /&gt;
* '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
* '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
* '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now. &lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
http://192.168.81.1:3480/data_request?id=jobstatus&amp;amp;job=13&lt;br /&gt;
&lt;br /&gt;
http://192.168.81.1:3480/data_request?id=jobstatus&amp;amp;job=6&amp;amp;plugin=zwave&lt;br /&gt;
&lt;br /&gt;
==invoke==&lt;br /&gt;
&lt;br /&gt;
==relay==&lt;br /&gt;
&lt;br /&gt;
This tells the system to setup a relay so that you can access a device on the home network from outside the home.  This is most commonly used to fetch streaming video from a camera, although it can actually be used for any IP device.  This takes either an 'ip' or 'device' argument.  If you pass a device, this is assumed to be a device ID, and the system will find the ip associated with that device.  Optionally pass a port argument for the port you want to be relayed.  Port 80 is assumed if none is specified.&lt;br /&gt;
&lt;br /&gt;
This request will return a 'server:port' which you can use externally to access the designated device.  The relay stays open for 15 minutes before closing, at which point you will need to open it again.&lt;br /&gt;
&lt;br /&gt;
So, assume you have a NAS device on the home network with the ip 192.168.1.55 and the NAS runs a configuration web page on port 80.  You could access it by doing this:&lt;br /&gt;
&lt;br /&gt;
data_request?ip=192.168.1.55&amp;amp;port=80&lt;br /&gt;
&lt;br /&gt;
and if the response is: &amp;quot;someserver:20202&amp;quot;, then for 15 minutes, &amp;quot;http://someserver:20202&amp;quot; will be the NAS's configuration page.&lt;br /&gt;
&lt;br /&gt;
If you want to access a camera, device #5, then do this:&lt;br /&gt;
&lt;br /&gt;
data_request?device=5&lt;br /&gt;
&lt;br /&gt;
and if the response is &amp;quot;someserver:20211&amp;quot; and if the 'DirectStreamURL' variable (or 'streaming' in sdata) is &amp;quot;video.mpeg&amp;quot;, then for 15 minutes you can access the camera's video at: http://someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
Note that if the device, the camera in this case, has http authentication, you will need to pass this too.  So, if the user_data or sdata for the camera shows the user name is 'johndoe' and the password is 'john123', then you can view the video at: http://john:john123@someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: For the 15 minutes while this relay is open, it will be open to anyone on the internet and public.  Therefore, for security, you may want to add to the data_request the argument externalip=x where x is the routable, external IP, such as 70.182.172.111, of the device that will be accessing the port.  This means that when the relay is open, a firewall will be set on the relay server so that incoming connections are only accepted from that ip address.&lt;br /&gt;
&lt;br /&gt;
==What to do when the HTTP request string is too long==&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php/topic,10170.msg69530.html#msg69530&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/AlternateEventServer</id>
		<title>AlternateEventServer</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/AlternateEventServer"/>
				<updated>2012-05-08T22:34:17Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vera calls Mios's event servers to report events, like sensor tripped, triggers, etc.  Mios's event servers send out text messages and emails to report these events.&lt;br /&gt;
 &lt;br /&gt;
Some very advanced users have asked to setup their own event server that Vera will call to report events.  If you add your own, alternate event server, Vera will still send events to Mios's event server unchanged, however Vera will also post the same event to the alternate server of your choice.&lt;br /&gt;
&lt;br /&gt;
Vera will send the event as a standard HTTPS (secure) GET to yourserver/alert with the arguments passed on the URL, like this (assuming your server is myserver.me.com):&lt;br /&gt;
&lt;br /&gt;
  https://myserver.me.com/alert?&lt;br /&gt;
   PK_AccessPoint=[serial number of Vera]&lt;br /&gt;
   &amp;amp;HW_Key=[hardware key of Vera]&lt;br /&gt;
   &amp;amp;DeviceID=[device id that is associated with the alert]&lt;br /&gt;
   &amp;amp;LocalDate=[the time the alert happened as human readable text]&lt;br /&gt;
   &amp;amp;LocalTimestamp=[the time the alert happened as a unix timestamp in UTC]&lt;br /&gt;
   &amp;amp;AlertType=[one of the alert types below]&lt;br /&gt;
   &amp;amp;SourceType=[one of the source types below]&lt;br /&gt;
   &amp;amp;Argument=[an optional argument depending on the alert type]&lt;br /&gt;
   &amp;amp;Format=[a file format, not normally used]&lt;br /&gt;
   &amp;amp;Code=[a code for the alert, usually the variable that changed]&lt;br /&gt;
   &amp;amp;Value=[the value corresponding to the code above]&lt;br /&gt;
   &amp;amp;Description=[a human readable description of the event, or comments regarding it]&lt;br /&gt;
   &amp;amp;Users=[a comma separated list of user id's that should be notified of the event]&lt;br /&gt;
&lt;br /&gt;
To turn this alternate event logging set the top level user_data tag &amp;quot;AltEventServer&amp;quot; to the domain of your server.  If your server is: myserver.me.com do this by changing the 'ip' to be the IP of Vera, and opening this URL:&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;Variable=AltEventServer&amp;amp;Value=myserver.me.com&lt;br /&gt;
&lt;br /&gt;
Then click reload in Vera's UI to reload the engine with the changes.  You can watch Vera send the data by logging into Vera's console as explained in [[Logon_Vera_SSH]] and then typing:&lt;br /&gt;
&lt;br /&gt;
tail -f /var/log/cmh/LuaUPnP.log | grep 'RAServerSync::SendAlert'&lt;br /&gt;
&lt;br /&gt;
To stop logging to your own server, call the variableset again but leave the Value empty.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/AlternateEventServer</id>
		<title>AlternateEventServer</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/AlternateEventServer"/>
				<updated>2012-05-08T22:20:30Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;Vera calls Mios's event servers to report events, like sensor tripped, triggers, etc.  Mios's event servers send out text messages and emails to report these events.   Some very ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vera calls Mios's event servers to report events, like sensor tripped, triggers, etc.  Mios's event servers send out text messages and emails to report these events.&lt;br /&gt;
 &lt;br /&gt;
Some very advanced users have asked to setup their own event server that Vera will call to report events.  If you add your own, alternate event server, Vera will still send events to Mios's event server unchanged, however Vera will also post the same event to the alternate server of your choice.&lt;br /&gt;
&lt;br /&gt;
Vera will send the event as a standard HTTPS (secure) GET to yourserver/alert with the arguments passed on the URL, like this (assuming your server is myserver.me.com):&lt;br /&gt;
&lt;br /&gt;
  https://myserver.me.com/alert?&lt;br /&gt;
   PK_AccessPoint=[serial number of Vera]&lt;br /&gt;
   &amp;amp;HW_Key=[hardware key of Vera]&lt;br /&gt;
   &amp;amp;DeviceID=[device id that is associated with the alert]&lt;br /&gt;
   &amp;amp;LocalDate=[the time the alert happened as human readable text]&lt;br /&gt;
   &amp;amp;LocalTimestamp=[the time the alert happened as a unix timestamp in UTC]&lt;br /&gt;
   &amp;amp;AlertType=[one of the alert types below]&lt;br /&gt;
   &amp;amp;SourceType=[one of the source types below]&lt;br /&gt;
   &amp;amp;Argument=[an optional argument depending on the alert type]&lt;br /&gt;
   &amp;amp;Format=[a file format, not normally used]&lt;br /&gt;
   &amp;amp;Code=[a code for the alert, usually the variable that changed]&lt;br /&gt;
   &amp;amp;Value=[the value corresponding to the code above]&lt;br /&gt;
   &amp;amp;Description=[a human readable description of the event, or comments regarding it]&lt;br /&gt;
   &amp;amp;Users=[a comma separated list of user id's that should be notified of the event]&lt;br /&gt;
&lt;br /&gt;
To turn this alternate event logging set the top level user_data tag &amp;quot;AltEventServer&amp;quot; to the domain of your server.  If your server is: myserver.me.com do this by changing the 'ip' to be the IP of Vera, and opening this URL:&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;Variable=AltEventServer&amp;amp;Value=myserver.me.com&lt;br /&gt;
&lt;br /&gt;
To stop logging to your own server, leave the Value empty.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Store_logs_USB</id>
		<title>Store logs USB</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Store_logs_USB"/>
				<updated>2012-05-08T15:18:18Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Validation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:User Instructions]]&lt;br /&gt;
[[Category:How To]]&lt;br /&gt;
'''HOWTO get your Vera log an attached USB drive.'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
On larger Vera deployments, with large numbers of Z-Wave Devices, Plugins or Scenes, it may be necessary to move the Vera log files to external storage to free-up space for Vera to function correctly.&lt;br /&gt;
&lt;br /&gt;
MiOS Version 1.1.1245 introduced an option to let users attach a standard USB drive to offload Vera's log files, the details are in the MiOS [[Release Notes]], inlined here:&lt;br /&gt;
&lt;br /&gt;
:''2. There is an option with Vera2 on Advanced, Logs to enable logging to a USB drive. This frees up quite a bit of memory, so if you have a lot of devices or plugins and your Vera is running slow or crashing because it's running out of memory, this is a solution. Note that after you check the box it can take up to 30 minutes to format the USB drive, and bootup will take a couple minutes longer with the USB drive installed. It will continue to boot up fine without the USB drive connected, just don't remove it while Vera is running. ''&lt;br /&gt;
&lt;br /&gt;
:''IMPORTANT: Use a new USB drive that hasn't already been formatted. In particular, don't use a USB drive that is already formatted for Mac''&lt;br /&gt;
&lt;br /&gt;
This [[:Category:How To|How To]] note shows you how to enable this option, how to validate that it's been enabled, and provides pointers to further reading.&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
This solution will requires:&lt;br /&gt;
* Vera 2 Hardware ''only''&lt;br /&gt;
* Firmware 1.1.1245 and above&lt;br /&gt;
* A ''new'' USB Drive&lt;br /&gt;
** Drive should be between 512Mb and 1Gb&lt;br /&gt;
** Vera will create its own partition on it which will be 512Mb in size and use that to write logfiles to it.&lt;br /&gt;
** Experienced users only: a ''newly'' FAT-formatted ''existing'' USB drive may work.  The jury is out on this one.&lt;br /&gt;
&lt;br /&gt;
==Instructions==&lt;br /&gt;
&lt;br /&gt;
* After you got your usb-drive connected to the USB port on the backside of your Vera.&amp;lt;br /&amp;gt;Please be patient, it might not work the first time, but it will work. DO NOT REMOVE THE DRIVE while Vera boots/reboots or during power-cycle operations.&lt;br /&gt;
* Log into the UI&lt;br /&gt;
* Select &amp;quot;Advanced&amp;quot; on the sop right (next to &amp;quot;MiOS developers&amp;quot; in the toolbox)&lt;br /&gt;
* Select the &amp;quot;Logs&amp;quot;tab&lt;br /&gt;
* Activate the &amp;quot;Store logs on USB device*&amp;quot; option and READ the text there:&lt;br /&gt;
: ''Please connect an USB drive first then check the checkbox.''&lt;br /&gt;
: ''WARNING: The USB drive will be erased. Wait 20 minutes after clicking OK.''&lt;br /&gt;
: ''Status'' &lt;br /&gt;
* Click the &amp;quot;OK&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
Wait until vera reports progress.&lt;br /&gt;
&lt;br /&gt;
If MiOS reports &amp;quot;FAILURE&amp;quot;, repeat the process.&lt;br /&gt;
If MiOS reports Success, you are done.&lt;br /&gt;
&lt;br /&gt;
==Validation==&lt;br /&gt;
For those who would like to validate it's setup correctly, here are some detailed steps.&lt;br /&gt;
&lt;br /&gt;
SSH into your vera (using Putty or any other SSH client)&lt;br /&gt;
Login as &amp;lt;tt&amp;gt;root&amp;lt;/tt&amp;gt; with the password thats on the back of your box. If you don't see the root password or need help logging in see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
At the prompt type:&lt;br /&gt;
  root@MiOS_1xxxx:~# df -h&lt;br /&gt;
&lt;br /&gt;
If you find something like:&lt;br /&gt;
  Filesystem                Size      Used Available Use% Mounted on&lt;br /&gt;
  ...&lt;br /&gt;
    /dev/scsi/host0/bus0/target0/lun0/part1&lt;br /&gt;
                          506.2M     29.2M    451.3M   6% /tmp/log/cmh&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
Then your USB drive is being used to storing MiOS log files.&lt;br /&gt;
&lt;br /&gt;
==Debugging==&lt;br /&gt;
&lt;br /&gt;
Check that /overlay isn't full.&lt;br /&gt;
&lt;br /&gt;
Stop LuaUPnP before activating 'Store logs on USB device*' (/etc/init.d/cmh stop).&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* USB Drive logging discussion [http://forum.micasaverde.com/index.php?topic=6439]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Logs</id>
		<title>Logs</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Logs"/>
				<updated>2012-05-08T15:18:03Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:User Instructions]]&lt;br /&gt;
[[Category:How To]]&lt;br /&gt;
&lt;br /&gt;
'''Logging explained'''&lt;br /&gt;
&lt;br /&gt;
Vera runs Linux and you can watch the logs if you want to see what's going with Vera.  This can be particularly helpful for debugging.&lt;br /&gt;
&lt;br /&gt;
First, you need to login to Vera using SSH.  If you have a Mac or Linux PC, SSH is built-in and you can open a console and enter:&lt;br /&gt;
&lt;br /&gt;
 ssh [ip address of vera]&lt;br /&gt;
&lt;br /&gt;
If you run Windows, get the utility Putty from here: [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html Putty Download] You do not need to install it, just download the file Putty.exe and run it.  In the Host Name box type in the IP address of Vera and click open.&lt;br /&gt;
&lt;br /&gt;
Either way you will have a console and be prompted for a username and password.  The username is: root  and the password is generally the wi-fi password (or the HomeID) printed on the sticker under Vera.  If you don't see the root password or need help logging in see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
Once you are logged in, type:&lt;br /&gt;
&lt;br /&gt;
 cd /var/log/cmh&lt;br /&gt;
&lt;br /&gt;
to get to the directory with the logs.  Then type:&lt;br /&gt;
&lt;br /&gt;
 tail -f LuaUPnP.log&lt;br /&gt;
&lt;br /&gt;
and you will see the logs scroll by as you do things with Vera.  Press Ctrl+C to stop watching the log.  Chances are there is too much data flying by to be useful, particularly if you turn on Verbose Logging (Vera's toolbox, Advanced, Logging).  So you will want to filter.  You can do this by adding &amp;quot;| grep&amp;quot; followed by whatever you want to filter for.  The most common use for this is that every line in the log starts with a 2 digit number indicating what type of event is being logged.  The most useful log entry is 04 which shows you the status of every &amp;quot;job&amp;quot; that Vera has completed (ie turning on a light, etc.) and the status of it.  To watch for the jobs type:&lt;br /&gt;
&lt;br /&gt;
 tail -f LuaUPnP.log | grep &amp;quot;^04&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and you will only see the lines that start with 04 (ie the jobs).  You can add more criteria by adding \|.  So, all commands (ie when you click on/off/etc.) on the dashboard start with 08.  So:&lt;br /&gt;
&lt;br /&gt;
 tail -f LuaUPnP.log | grep &amp;quot;^04\|^08&amp;quot;&lt;br /&gt;
&lt;br /&gt;
will show you when Vera got a command to do something and when Vera finished doing it.  This is helpful for debugging what's going on.  Following is a screen capture from putty that shows what happens when you turn on a device from the dashboard:&lt;br /&gt;
&lt;br /&gt;
 root@MiOS_10266:/tmp/log/cmh#  tail -f LuaUPnP.log | grep &amp;quot;^04\|^08&amp;quot;&lt;br /&gt;
 08      08/13/10 20:49:58.469   JobHandler_LuaUPnP::HandleActionRequest device: 100 service: urn:upnp-org:serviceId:SwitchPower1 action: SetTarget &amp;lt;0x11008&amp;gt;&lt;br /&gt;
 08      08/13/10 20:49:58.469   JobHandler_LuaUPnP::HandleActionRequest argument DeviceNum=100 &amp;lt;0x11008&amp;gt;&lt;br /&gt;
 08      08/13/10 20:49:58.470   JobHandler_LuaUPnP::HandleActionRequest argument serviceId=urn:upnp-org:serviceId:SwitchPower1 &amp;lt;0x11008&amp;gt;&lt;br /&gt;
 08      08/13/10 20:49:58.471   JobHandler_LuaUPnP::HandleActionRequest argument action=SetTarget &amp;lt;0x11008&amp;gt;&lt;br /&gt;
 08      08/13/10 20:49:58.472   JobHandler_LuaUPnP::HandleActionRequest argument newTargetValue=1 &amp;lt;0x11008&amp;gt;&lt;br /&gt;
 04      08/13/10 20:49:59.312   &amp;lt;Job ID=&amp;quot;23&amp;quot; Name=&amp;quot;ON node 20&amp;quot; Created=&amp;quot;10-08-13 20:49:58&amp;quot; Started=&amp;quot;10-08-13 20:49:58&amp;quot; Completed=&amp;quot;10-08-13 20:49:59&amp;quot; Duration=&amp;quot;0.742113000&amp;quot; Runtime=&amp;quot;0.695043000&amp;quot; Status=&amp;quot;Successful&amp;quot; LastNote=&amp;quot;Transmit was ok&amp;quot; Node=&amp;quot;20&amp;quot; Device=&amp;quot;100&amp;quot; NodeType=&amp;quot;ZWaveNonDimmableLight&amp;quot; NodeDescription=&amp;quot;_Switching Plugin&amp;quot;/&amp;gt; &amp;lt;0x402&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see that the command came in for device #100 20:49:58.469 (meaning 469/1000's of a second).  The action was &amp;quot;SetTarget&amp;quot; for the &amp;quot;SwitchPower&amp;quot; service (meaning set the power state on or off), and the newTargetValue=1 means it's coming on.  You can see that Vera created a job #23 to do this, and that at 20:49:59.312 the job completed and was successful.  The ZWave node id is 20.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/View_Logfiles</id>
		<title>View Logfiles</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/View_Logfiles"/>
				<updated>2012-05-08T15:17:24Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:User_Instructions]]&lt;br /&gt;
[[Category:How To]]&lt;br /&gt;
&lt;br /&gt;
Vera runs Linux, and stores the logs in /var/log/cmh.  They are ANSI color coded, meaning you need to view them with less -R.  Note that the Linux distro that comes with Vera doesn't support less -R, so you need to copy them to another computer to view them.  To do this:&lt;br /&gt;
&lt;br /&gt;
1.  Login to Vera's console as explained here: [[Logon_Vera_SSH]].&lt;br /&gt;
&lt;br /&gt;
2.  Copy the logs from /var/log/cmh using scp.  Windows users can use the free WinSCP utility.  Note that once the logs hit 2MB they are automatically either deleted or archived on our servers if you left that option checked on Advanced, Logs.&lt;br /&gt;
&lt;br /&gt;
3a.  To view them on a Unix/Linux system, use less -R and the log file.&lt;br /&gt;
&lt;br /&gt;
3b.  To view them on a Windows PC, download this file: http://download.controlmyhouse.net/less.zip and unzip the contents into a directory, preferably under c:\ so it's easy to get to from a command prompt.  Choose Start, run, and enter CMD to bring up a command prompt.  Then type: cd \less (or whatever directory you put it in).  Put the log files in the same directory.  Before starting it you might want to click the control button in the upper left of the command prompt, choose Properties, Layout, and increase the window size to 160 wide.  Then enter: ''less -R [filename]''.  You may see an error and have to hit enter.  This is OK.  Once the log appears, the letters u and d scroll up and down, and q exits.  The / key lets you search, although for some reason it doesn't always work.  If you want the most full featured version of less, install cygwin, which is what less.zip came from.  If you have turned verbose logging on in Vera, the logs will also contain a trace of all the ZWave data going to/from the ZWave chip.  Lines starting with 41 are outgoing and color coded red, 42 is incoming and yellow.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Somfy_Walkthrough</id>
		<title>Luup Somfy Walkthrough</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Somfy_Walkthrough"/>
				<updated>2012-05-08T15:16:45Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Step 1: SSH into Vera */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
This page is for developers wanting to learn how to write a plugin.  If you simply want to use the Somfy plugin see: [[Somfy_Plugin]]&lt;br /&gt;
&lt;br /&gt;
This page walks through in detail the process of creating a Luup plugin to control the Somfy RS232 interface for motorized blinds as a sample.  The Somfy documentation (see: [http://www.blindshademotors.com/documents/accessories-special-applications/rs232-to-rts-compatability.pdf]) explains that you talk to the controller using RS232 9600 Baud, 8 Data Bits, 1 Stop Bit, No Parity.  The interface supports up to 16 blinds.  The communication is one-way only; there are no response codes or incoming data from the blinds when they change manually.  Here is the relevant section from the manual.&lt;br /&gt;
&lt;br /&gt;
 RS232 Operation&lt;br /&gt;
 1. Set RS232 communication settings to: 9600 Baud, 8 Data Bits, 1 Stop Bit, No Parity&lt;br /&gt;
 2. Use the ASCII protocol command string syntax: &amp;lt;!&amp;gt; &amp;lt;2 digit channel number&amp;gt; &amp;lt;Directional Command&amp;gt;&lt;br /&gt;
 3. The directional commands must be capital letters and are as follows:&lt;br /&gt;
   U: UP&lt;br /&gt;
   D: DOWN&lt;br /&gt;
   S: STOP&lt;br /&gt;
 4. Examples: Motor 2 Up: !02U&lt;br /&gt;
   Motor 5 Down: !05D&lt;br /&gt;
   Motor 1 Stop: !01S&lt;br /&gt;
&lt;br /&gt;
==Step 1: SSH into Vera==&lt;br /&gt;
&lt;br /&gt;
Since this device is so simple it may not be necessary to debug anything.  But we'll do this anyway.  You need to give Vera a root password, which is the administrator password to login directly.  Do this by either: a) from a command prompt in Windows, Linux or Mac type telnet [ip address of vera] and when you see the ''root@HomeControl:~#'' prompt enter: ''passwd'' and type in a password twice.  Then type exit.  Or b) In Vera's web ui click Advanced, Net &amp;amp; Wi-fi and the 'Advanced Configuration' link, and supply the password there.  Note, sometimes Windows Vista doesn't have the telnet utility installed, so you have to use step b.&lt;br /&gt;
&lt;br /&gt;
Once you have a root password set, you will no longer be able to use telnet to login to Vera, you must use ssh.  The reason you should use ssh to login for debugging, and not telnet, is because some of the useful key sequences, like Ctrl+C, don't work in telnet.&lt;br /&gt;
&lt;br /&gt;
Once you've setup a root password, from a Mac or Linux console type: ''ssh [ip of vera]''  From a Windows PC, download putty.exe here: [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html].  You don't need to install putty, just put the .exe on your desktop or in a folder.  When you run putty.exe, type in Vera's IP address and click 'open'.  If you don't see the root password or need help logging in see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
When you see ''login as:'', enter: ''root'' and then enter your password.  Now from the ''root@HomeControl:#'' prompt type:&lt;br /&gt;
&lt;br /&gt;
  cd /var/log/cmh&lt;br /&gt;
  tail -f LuaUPnP.log&lt;br /&gt;
&lt;br /&gt;
Do something in Vera's web ui and you'll see the logs go.  Whenever the system rotates the logs, meaning purges the log files because Vera's memory is limited for storing logs, your tail will end.  Press the 'up' arrow and hit 'enter' to display the tail command again and restart it.  Press Ctrl + c when you've confirm the logs are working ok.&lt;br /&gt;
&lt;br /&gt;
In Vera's web ui, choose Advanced, Logs, and check 'Verbose logging'.  This option will create large logs that have lots of information we may need for debugging.  It will stay checked for 24 hours and then automatically turn itself off so you're not creating unnecessarily large log files.&lt;br /&gt;
&lt;br /&gt;
==Step 2a: Add your device with the web generator tool==&lt;br /&gt;
&lt;br /&gt;
  --coming soon.  for now use step 2b.&lt;br /&gt;
&lt;br /&gt;
== Step 2b: Add your device by building the XML files by hand ==&lt;br /&gt;
&lt;br /&gt;
To do this you'll want a good text editor. I'm using, such as Notepad++ available here: [http://notepad-plus.sourceforge.net/uk/site.htm] by clicking Download, Download Notepad++ executable files, download and run the npp....Installer.exe file, and you may also want to download the 'XML plugin' from the download page, and unzip it putting the file \Program Files\Notepad++\plugins. &lt;br /&gt;
&lt;br /&gt;
In Vera's setup UI, go to Devices, Luup plugins, click 'Luup files' and download the files: &lt;br /&gt;
&lt;br /&gt;
''D_BinaryLight1.xml'' since there is no UPnP device specification for blinds, and blinds are essentially binary devices that are either up/down, we can implement the up/down using the same service that a light switch uses, and that way any UPnP control point that can control a light switch, will also be able to control blinds. &lt;br /&gt;
&lt;br /&gt;
''S_SwitchPower1.xml'' because when you open D_BinaryLight1.xml, you'll see that in the 'services' section, this is the filename (SCPDURL) for the SwitchPower service. &lt;br /&gt;
&lt;br /&gt;
[[Media:D_TestSerial.zip | ''D_TestSerial.xml'']] because this is a sample serial device we can use as a template. &lt;br /&gt;
&lt;br /&gt;
[[Media:I_TestSerial.zip | ''I_TestSerial.xml'']] because this is a sample implementation for our serial device. &lt;br /&gt;
&lt;br /&gt;
Open D_TestSerial.xml in your text editor and re-save it as a different name, such as D_SomfyBlinds.xml. Change the xml field deviceType to &amp;quot;urn:somfy-com:device:blinds:1&amp;quot; or use your own domain name instead of somfy-com. Change friendlyName to &amp;quot;Somfy Blind Controller&amp;quot;, manufacturer to &amp;quot;Somfy&amp;quot;, manufacturerURL to &amp;quot;somfy.com&amp;quot;, modelDescription to &amp;quot;16 port RS232 to Somfy blind interface&amp;quot;, modelName to &amp;quot;1810686&amp;quot; (the Somfy part number). modelURL and serialNumber and UPC aren't really important so you can just remove them. Add in their place a protocol tag with the value 'raw', and handlechildren (we'll explain this one later) with the value 1, like this: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;protocol&amp;gt;raw&amp;lt;/protocol&amp;gt;&lt;br /&gt;
  &amp;lt;handleChildren&amp;gt;1&amp;lt;/handleChildren&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 'raw' protocol is because the Somfy device doesn't have any particular low level protocol, like terminating blocks of data with a carriage return, etc. Remove all the tags in 'servicelist'. &lt;br /&gt;
&lt;br /&gt;
Change the filename in the ''implementationFile'' tag from I_TestSerial.xml to I_SomfyBlinds.xml. &lt;br /&gt;
&lt;br /&gt;
Open I_TestSerial.xml and delete the sample Lua code within the 'actionList' tag. We have to put some Lua code in the implementation file for the Luup engine to start it, so for now just put a placeholder in the 'functions' xml tag: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function lug_startup(lul_device)&lt;br /&gt;
    luup.log(&amp;quot;Somfy blind #&amp;quot; .. lul_device .. &amp;quot; starting up with ID &amp;quot; .. lug_device[lul_device].ID)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and in the 'startup' xml tag, put: ''lug_startup'', like this: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;startup&amp;gt;lug_startup&amp;lt;/startup&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we've created a Lua function, lug_startup, told the Luup engine to call it when the engine is starting up. The name lug_startup is arbitrary, it can be anything you want. Save the file as I_SomfyBlinds.xml. &lt;br /&gt;
&lt;br /&gt;
Back on Vera's setup ui under 'Luup files' you the first 'upload' button to upload D_SomfyBlinds.xml and the 2nd to upload I_SomfyBlinds.xml. Check ''Restart Luup after upload'' because the files won't be processed unless we restart the Luup engine, and click 'go'. Now leave your browser tab open at this page so that as we change the implementation file we can just click 'go' without having to select the files again. &lt;br /&gt;
&lt;br /&gt;
In another browser tab go to Vera's device page again and under 'Add device' put the new device filename ''D_SomfyBlinds.xml'' in the input box, and choose the room where the blind controller is located, click 'Add device'. You'll have a new, blank device in that room, so give it a description &amp;quot;Somfy Blind Controller&amp;quot;, then click 'save'. &lt;br /&gt;
&lt;br /&gt;
Note that if the Somfy device was bi-direction we should attempt to communicate with it during the startup sequence and the startup function should return false if the sequence failed, or true if it succeeded, followed by some comments and the name of the module, which information is shown to the user in the info panel. So: return false,'Interface not responding','Somfy Blind' or return true,'Initialized OK','Somfy Blind'&lt;br /&gt;
&lt;br /&gt;
==Step 3: Setup the port==&lt;br /&gt;
&lt;br /&gt;
Vera talks to serial devices using a serial port proxy that turns the serial port into a network port.  This way the serial port can reside anywhere on the network.  Here are 3 ways to connect Vera to the Somfy device:&lt;br /&gt;
&lt;br /&gt;
1.  Get the UC232R-10 usb-&amp;gt;serial adapter here: [http://www.futureelectronics.com/en/Pages/index.aspx]  Connect it to one of Vera's USB ports.  In Vera's web ui, click the 'save' button, which, even if the 'save' button is grayed out, causes the Luup engine to re-initialize and scan for new serial ports.  Wait 30 seconds.&lt;br /&gt;
&lt;br /&gt;
2.  Use any Windows COM port or USB-&amp;gt;serial port device.  Download [[Windows_Serial_Proxy]] and run it as explained there.  Wait 30 seconds after running it and it will exit after it has reported the port to the Luup engine.&lt;br /&gt;
&lt;br /&gt;
3.  Connect a Global Cache GC-100 to your network.  Wait 30 seconds or so for the Luup engine to find it.  This should happen automatically.  Bring up the GC100's setup page in your web browser; you can find the IP address in Vera's device page under the + sign, and set the baud/parity/etc. for the port to match.  In the case of the GC-100, this information is supplied to the GC-100 itself and the values in the Serial Port Configuration page have no effect.&lt;br /&gt;
&lt;br /&gt;
After you've done 1, 2 or 3, go to Devices, Luup plugins and click &amp;quot;Serial port configuration&amp;quot;.  The serial port should be on the list.  Use the pull-down's to set the serial port options: baud=9600, Data Bits=8, Stop Bits=1, Parity=none.  For the 'Use with device', select your Somfy Blind controller.  Choose 'Save'.&lt;br /&gt;
&lt;br /&gt;
==Step 4: Test the port==&lt;br /&gt;
&lt;br /&gt;
First, make note of the device id for your Somfy blinds by clicking '+' next to the device in the device list.  Next, go to Devices, Luup Plugins, Test Luup code.  In the 'Device number' input box put the device number for the Somfy blinds.  This way whatever code we test uses the Lua instance for the Somfy blinds, which will be configured already to use the serial port.&lt;br /&gt;
&lt;br /&gt;
In the 'Code' input box, type: ''luup.io.write('!01U')'' and click 'Go'.  That is a command according to the Somfy specs, which should make motor #1 go up.  You can try other commands and click 'Go' each time.  If everything is working ok, skip to step 6.  If it's not working, you will want to do some debugging.  Here's some debug things to try:&lt;br /&gt;
&lt;br /&gt;
1.  Be sure you checked 'Verbose logging' in Step 1. In your ssh console (ie putty if you're using windows) enter ''tail -f LuaUPnP.log | grep '^5\|^01' '' where the | means to send the output through the grep utility, which will filter out only certain lines.  The ^ means 'lines that start with'.  Line that start with 5 are logs related to Lua, and lines that start with 01 are critical errors.  The \| means 'or' for grep.  Now go back and click 'go' again in the Test Luup window.  Return to the ssh console and you should see a line that starts with 51, which means data sent within Luup, that shows !01U, in this format: ''51      06/29/09 17:19:53.453   0x21 0x30 0x31 0x55 0xd 0xa (!01U\r\n)'', where the human-readable ascii text is in () at the end, following the binary/hex.  If you're going to be switching back and forth between the ssh console and web ui to do tests, then before you switch to the web ui, you can either hit 'enter' a few times in the ssh console to add some blank space, or press Ctrl+c and then 'up' followed by 'enter' to restart tail.  That way you've created some separation between existing log entries and new ones so you can clearly see what is happening when you click 'go'.  If you're not seeing anything, in the Test Luup window add the line ''lu_log('test somfy')'' above the luup.io.write.  You should see 'test somfy' get logged when you press 'go'.&lt;br /&gt;
&lt;br /&gt;
2.  Assuming you do see the line '51' log entry showing that the Luup engine is trying to send data, you may want to check the serial port itself.  You can go back to the 'serial port configuration' and remove the 'Somfy blind' device from the serial port so the Luup engine won't open the port.  Make a note of the network ip and port for the serial port.  Click 'Save' to save your changes.  Now from a command prompt run: ''telnet [ip] [port]''.  If you don't have telnet, open another putty session and click the 'telnet' radio box, put in the ip address and port and click 'open'. You should now be able to type the commands in the telnet session: ''!01U'' and see the blinds work.  If it still doesn't work, try connecting the blinds directly to your PC and using a terminal program, like Hyperterminal, to talk directly to the serial port and confirm the connections are ok.&lt;br /&gt;
&lt;br /&gt;
==Step 5: Create the child devices for the blinds ==&lt;br /&gt;
&lt;br /&gt;
In Luup, when you have an interface device which is able to control multiple devices this is represented as a tree where the interface is a 'virtual' device, that probably doesn't implement any actions itself, and multiple 'child devices' under the interface device for each device the interface can control.  The Somfy Blind controller is such a device because the 1 interface can control 16 blinds.  If it only controlled 1 blind, we wouldn't need to implement the parent/multiple child architecture, because we would have just 1 device which implemented the blind functions.  We also wouldn't need to create any functions in Lua and we'd simply have put the control protocol in the 'action' tags in the implementation XML.  But we want a parent 'Somfy interface' with up to 16 different child devices for each of the 16 blinds the device can control.  This means it's a bit more complicated, so we'll want to use Lua functions, like 'lug_startup'.&lt;br /&gt;
&lt;br /&gt;
The way to implement multiple children is with the 'Reporting child devices' commands documented in [[Luup_Lua_extensions]].  This is how a parent device, in this case the Somfy blind interface, reports to the Luup engine what child devices it has and what ID number it will use internally to keep track of each one.  Every device in Luup has an &amp;quot;ID&amp;quot; value which has no meaning to the Luup engine itself, but which is used by parent devices to keep track of the children.  Many interface devices have a way to get from them the list of child devices so the parent can manage the children automatically.  The Somfy doesn't.  So we have 2 choices: 1) Just automatically report 16 child devices since the interface supports 16 devices, or 2) Let the user indicate which Somfy blind numbers he has and report just those child devices.  The advantage of #1 is that it's very simple, but the drawback is that the user will see 16 blinds in his home, even if he only has 1.  So, we will do it with #2.  The first question is where to let the user store the list of blind numbers that are active.  The usual way to store this information is to create a UPnP service which contains variables for all the various parameters the user should specify to configure the device.  Creating a UPnP service description document and adding it to the device description is a lot of work to get only 1 parameter: a list of device numbers.  But, what we can do is instead just create a variable in Lua using some service id/variable we made up, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_ID, lul_device)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This won't be an 'official' UPnP variable and won't show up in a UPnP scanner.  But, it does show up in Vera's user interface as a variable the user can edit the value.  We want to be sure we set this to a default value if it's not already there so the user sees it in the UI and can change it.&lt;br /&gt;
&lt;br /&gt;
Now we'll add the Lua code to iterate through all the blinds and create the devices, which will go in the lug_startup function we created earlier.  We could put the code directly in the XML implementation file.  But that means saving/uploading the file each time, and is a bit more tedious.  It's often easier to debug it first in the 'Test Luup code' window.  So we'll this to test first.  First, put in the code box: ''lug_startup(123)'' but change the 123 to the actual device number of the Somfy blind, and click 'go'.  Switch back to the ssh console that is tail'ing the LuaUPnP.log.  You'll see that it logged ''Somfy blind #... starting up with ID''.  This is because we already created the lug_startup function in the implementation file, and in the code box we just called that function.  Now put this in the code box:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function lug_startup(lul_device)&lt;br /&gt;
    local lul_ID=&amp;quot;01,02&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;,&amp;quot;BlindIds&amp;quot;, lul_ID, lul_device)&lt;br /&gt;
    luup.log(&amp;quot;test2--Somfy blind #&amp;quot; .. lul_device .. &amp;quot; starting up with ID &amp;quot; .. lul_ID)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  lug_startup(123)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 123 should be your actual device number for the device.  The Lua code in ''function lug_startup'' will cause the lug_startup function that was already in the implementation file to be replaced with this version, without actually executing the function (just updating it), so afterward we also have lug_startup(123) to actually run the new version we updated.  When you click 'go' you'll see in the ssh log that the it now says ''test2--Somfy blind'', so you can see the lug_startup function was replaced.  Note that any functions you create in the 'Test Luup Code' window will still stay in the Luup engine until you reload the Luup engine.  So if you type in the code box:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function some_test()&lt;br /&gt;
    luup.log(&amp;quot;some_test&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
click 'go', nothing will get logged.  If you then erase the code box and type: ''some_test()'' when you click 'go', you'll see &amp;quot;some_test&amp;quot; in the log.  If you want to update the some_test function, and run it at the same time, do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function some_test()&lt;br /&gt;
    luup.log(&amp;quot;some_test2&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  some_test()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when you click 'go', you'll see &amp;quot;some_test2&amp;quot; be logged.  So we'll create a simple startup that creates all 16 blinds by putting this in the Test Luup code window:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function lug_startup(lul_device)&lt;br /&gt;
    child_devices = luup.chdev.start(lul_device);&lt;br /&gt;
    for i = 1,16 do&lt;br /&gt;
      s = string.format(&amp;quot;%02d&amp;quot;, i)&lt;br /&gt;
      luup.log(&amp;quot;Adding blind &amp;quot; .. s)&lt;br /&gt;
      luup.chdev.append(lul_device, child_devices, s, &amp;quot;Blind #&amp;quot; .. s, &amp;quot;urn:schemas-upnp-org:device:BinaryLight:1&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, true)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    luup.chdev.sync(lul_device, child_devices)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  lug_startup(123)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ''for i=1,16'' is runs the block before 'end' 16 times, assigning the variable 'i' to 1 to 16 each time.  We want the devices to be 0 padded to 2 digits, so 1 should be &amp;quot;01&amp;quot;.  This is because the ID which the Somfy needs is a zero-padded 2 digit number.  It also will make it easier to filter just the blinds we want to control as explained later.  The statement ''s = string.format(&amp;quot;%02d&amp;quot;, i)'' converts the numeric value 'i' to a string that is padded to decimal places.  This is documented in Lua (see [http://www.lua.org/pil/20.html#StringLib]).&lt;br /&gt;
&lt;br /&gt;
luup.chdev.start() takes as a parameter our device id (ie the parent device) and it tells the Luup engine we're going to start listing all our children.  It returns a handle which we pass in to to the other chdev_ functions.  luup.chdev.append() adds each child and it takes the parent device number, the handle from lu_chdev_start, the id the parent will use to identify the device (s=01, 02, etc.), and the device type.  This is a UPnP device.  We'll use the existing UPnP standard &amp;quot;Binary light&amp;quot; because this way every UPnP control point will treat the blinds as a light and show the user an 'on' and 'off' button.  We could create our own device type for blinds which had actions &amp;quot;open&amp;quot; and &amp;quot;close&amp;quot;, but then the UPnP Control Points (like the iPhone interface) would need to be updated to know how to present the user with blinds.  luup.chdev.sync() is called when we're done to synchronize the child device list with Luup's database, and create/remove any new/missing devices, and restart the Luup engine if devices were added or removed.  See: [[Luup_Lua_extensions]]&lt;br /&gt;
&lt;br /&gt;
Before you click 'go', restart your tail in the ssh window with: ''tail -f LuaUPnP.log | grep '^5\|^01\|^03\|^09\|^11' '' because the 03 logs indicate when the Luup engine stops and restart, the 09 logs show us when devices are created/deleted, and the 11 logs show when the child device functions are calls.  Now when you click 'go', you should see in the logs ''Child_Devices::AddChild'' is called 16 times, and then 16 times ''Child_Devices::ProcessChildDevice created device''.  You should also see lines starting with '03' that show the Luup engine is reloading since new devices were just created.  When it restarts, you'll see 16 new devices in the logs starting with 09.&lt;br /&gt;
&lt;br /&gt;
Now if you click 'go' again, you'll see 16 logs for ''Child_Devices::AddChild'', but no devices will be created or removed because the 16 devices were already created, and the parent/child device lists are still in sync.  We have the same 16 child devices with no new ones or removed ones.&lt;br /&gt;
&lt;br /&gt;
Now if you refresh Vera's web UI, you'll see the Somfy device has '16' embedded devices, each with &amp;quot;on&amp;quot; and &amp;quot;Off&amp;quot;.  The 'true' at the end of the luup.chdev.append means the child devices are 'embedded'.  That means when they're shown in Vera's web UI, they're all grouped together as one compound device.  If you changed the 'true' to a 'false', all 16 blinds would show up as completely separate devices.  This is really just a cosmetic difference.  The advantage to using 'false' (non-embedded) is that the user can put each blind in a different room.  In this case it's probably better to treat the devices as non-embedded, since it is likely the 16 blinds will be scattered around the house.  So change the true at the end of luup.chdev.append to a false.  Then click 'go'.  Now, the 16 blinds are removed, and re-added as non-embedded devices.  So, if you refresh Vera's web UI and go to devices, you'll 16 different blinds that you can put into different rooms, in addition to the &amp;quot;Somfy blind interface&amp;quot; device.&lt;br /&gt;
&lt;br /&gt;
Next, we'll update our Lua code to only create child devices that are specified in the &amp;quot;ID&amp;quot; parameter of the &amp;quot;Somfy blind interface&amp;quot; so that if the user doesn't have 16 devices he can specify just the ones he does have.  To make our coding easier, we'll document in the notes for the user that when specifying the list of blinds in the &amp;quot;ID&amp;quot; he must use 01,02, etc., rather than 1,2, etc. because by storing all child devices as 2 digits, we can do a simple search without having to actually parse the ID.  In other words, if we want to know if blind #1 is active, we can safely search the ID for 01 and know that it will only match if blind #1 is active.  If the user stored single digit blind numbers, like ''5,6,11'' then searching for '1' would give us a false positive and we'd need to write more Lua code to break the list apart.  This also makes it easier to send the blind commands because the Somfy protocol says the blind number must be 2 digits, so we won't need to pad the ID's with 0 for the Somfy device.  This is why we did the for loop with 16 text strings using string.format which would have given us normal, non-zero-padded numbers.&lt;br /&gt;
&lt;br /&gt;
Put a -- in front of the luup.chdev.append in the window and click 'go' again.  -- means &amp;quot;comments&amp;quot; in Lua, and lines starting with -- are ignored.  Therefore, by eliminating the luup.chdev.append, now the luup.chdev.sync will remove all 16 children since none were appended.  This way we can reload Vera's web UI, go to the devices page, and we won't have those 16 blinds anymore requiring us to provide a room.  Click '+' next to the Somfy blind interface, click 'Advanced' and in the BlindIds enter: '02,07,13', click 'save'.  Now in the 'Test Luup code' window enter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function lug_startup(lul_device)&lt;br /&gt;
    local lul_ID = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_device)&lt;br /&gt;
    if (lul_ID == nil) then&lt;br /&gt;
      lul_ID = &amp;quot;01,02&amp;quot;&lt;br /&gt;
      luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_ID, lul_device)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local lul_prefix = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;UrtsiId&amp;quot;, lul_device)&lt;br /&gt;
    if (lul_prefix == nil) then&lt;br /&gt;
      lul_prefix = &amp;quot;01&amp;quot;&lt;br /&gt;
      luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;UrtsiId&amp;quot;, lul_prefix, lul_device)&lt;br /&gt;
   end&lt;br /&gt;
&lt;br /&gt;
   luup.log(&amp;quot;Somfy ID is &amp;quot; .. lul_ID .. &amp;quot; prefix is &amp;quot; .. lul_prefix)&lt;br /&gt;
   child_devices = luup.chdev.start(lul_device);&lt;br /&gt;
   for i = 1,16 do&lt;br /&gt;
     s = string.format(&amp;quot;%02d&amp;quot;, i)&lt;br /&gt;
     if (string.find(lul_ID,s) ~= nil) then&lt;br /&gt;
       luup.log(&amp;quot;Adding blind &amp;quot; .. s)&lt;br /&gt;
       luup.chdev.append(lul_device, child_devices, s, &amp;quot;Blind #&amp;quot; .. s, &amp;quot;urn:schemas-upnp-org:device:BinaryLight:1&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, false)&lt;br /&gt;
     end&lt;br /&gt;
   end&lt;br /&gt;
&lt;br /&gt;
   luup.chdev.sync(lul_device, child_devices)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
 lug_startup(123)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don't forget to change the '123' to your actual device number.  Now when you click 'go' you'll see the logs indicate we only have 3 blinds with ID's 02, 07 and 13.  Since this part of the code is done, you can copy/paste this from the Luup test code window into the implementation.  '''IMPORTANT:''' Be sure the ''lug_startup(123)'' is NOT in your implementation file, or else your lug_startup function will be called twice at each startup: once by the Luup engine with the actual device number, and once when the startup functions are loaded into the Lua engine with your hard-coded number used for testing, which won't necessarily correspond to the real device number.  We also add the variable lul_prefix because the URTS version 1 takes an ! in the front of every command, whereas with version 2 it's a 2 digit number from 01 to 16.  So we'll default to 01, the default value for an URTS version 2, but we'll let the user change it.  We'll store this in a global variable, lul_prefix, so it's available for use in the other functions in our plugin.&lt;br /&gt;
&lt;br /&gt;
If you're editing the XML file by hand, you can save your changes and click 'go' in the Luup files upload page in your web browser to upload your changes.&lt;br /&gt;
&lt;br /&gt;
Every time you re-start the Luup engine, such as clicking 'Save', you'll see in the logs this startup sequence.&lt;br /&gt;
&lt;br /&gt;
==Step 5b: Polish up the startup sequence ==&lt;br /&gt;
&lt;br /&gt;
The the startup sequence as it is the user will always think the Somfy module loaded fine, even when it didn't, giving the user a false sense that everything was ok even when he hadn't yet specified basic parameters.&lt;br /&gt;
&lt;br /&gt;
Now, the code first checks for basic startup parameters, which are stored in UPNP variables, and sets them to a default value if they're not already specified.  You should at least set them an empty string because by setting them to something then the user will see them in the web user interface and be able to easily change them, as opposed to creating them again from scratch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local lul_ID = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_device)&lt;br /&gt;
  if (lul_ID = nil) then&lt;br /&gt;
    lul_ID = &amp;quot;01,02&amp;quot;&lt;br /&gt;
    luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_ID, lul_device)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, since this device uses an IO Port (ie a serial port, or an ethernet port, or a usb connection), we should check that the connection is specified and is active before doing the startup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  if (luup.io.is_connected(lul_device) == false) then&lt;br /&gt;
    luup.log('No port for Somfy', 1)&lt;br /&gt;
    luup.task('Choose the Serial Port for the URTSI', 2, 'Somfy Blind Interface', -1)&lt;br /&gt;
    return false&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there's a failure of any kind, we should call luup.task and put in some sort of description with the status code 2 (Error), and then 'return false'.  This way the user sees in the web panel that the module 'Somfy Blind Interface' is in an error condition and what the problem is (he didn't choose the serial port).  If we didn't do the 'return false', the user would think the Somfy module was ok since, when the startup function doesn't return false, the architecture assumes the module is running fine.  If we called return false, didn't call luup.task, then the user see that the module was failing, but would have only a generic &amp;quot;Startup sequence failed&amp;quot; without knowing the explicit reason.&lt;br /&gt;
&lt;br /&gt;
So now the startup sequence looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  function lug_startup(lul_device)&lt;br /&gt;
    local lul_ID = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_device)&lt;br /&gt;
    if (lul_ID == nil) then&lt;br /&gt;
      lul_ID = &amp;quot;01,02&amp;quot;&lt;br /&gt;
      luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;BlindIds&amp;quot;, lul_ID, lul_device)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local lul_prefix = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;UrtsiId&amp;quot;, lul_device)&lt;br /&gt;
    if (lul_prefix == nil) then&lt;br /&gt;
      lul_prefix = &amp;quot;01&amp;quot;&lt;br /&gt;
      luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SomfyBlinds1&amp;quot;, &amp;quot;UrtsiId&amp;quot;, lul_prefix, lul_device)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    luup.log(&amp;quot;Somfy ID is &amp;quot; .. lul_ID .. &amp;quot; prefix is &amp;quot; .. lul_prefix)&lt;br /&gt;
&lt;br /&gt;
    if (luup.io.is_connected(lul_device) == false) then&lt;br /&gt;
      luup.log('No port for Somfy', 1)&lt;br /&gt;
      luup.task('Choose the Serial Port for the URTSI',2,'Somfy Blind Interface', -1)&lt;br /&gt;
      return false&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    child_devices = luup.chdev.start(lul_device);&lt;br /&gt;
    for i = 1,16 do&lt;br /&gt;
      s = string.format(&amp;quot;%02d&amp;quot;, i)&lt;br /&gt;
      if (string.find (lul_ID,s) ~= nil) then&lt;br /&gt;
        luup.log(&amp;quot;Adding blind &amp;quot; .. s)&lt;br /&gt;
        luup.chdev.append(lul_device, child_devices, s, &amp;quot;Blind #&amp;quot; .. s, &lt;br /&gt;
                          &amp;quot;urn:schemas-micasaverde-com:device:WindowCovering:1&amp;quot;,&lt;br /&gt;
                          &amp;quot;D_WindowCovering1.xml&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, false)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    luup.chdev.sync(lul_device, child_devices)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Step 6a: Implementation the actions in the web generator ==&lt;br /&gt;
&lt;br /&gt;
--coming soon--&lt;br /&gt;
&lt;br /&gt;
==Step 6b: Implementation the actions in the xml file ==&lt;br /&gt;
&lt;br /&gt;
The reason we added the ''&amp;lt;handleChildren&amp;gt;1&amp;lt;/handleChildren&amp;gt;'' tag to the Somfy blind interface's device file earlier is because we're going to put all the actions for the child devices (the blinds) within the main implementation file for the Somfy.  So, whenever an action comes in for a child device (a blind), the Lua code in the parent devices implementation file will handle it.  Replace the actionList tag in the implementation file with this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;actionList&amp;gt;&lt;br /&gt;
    &amp;lt;action&amp;gt;&lt;br /&gt;
      &amp;lt;serviceId&amp;gt;urn:upnp-org:serviceId:SwitchPower1&amp;lt;/serviceId&amp;gt;&lt;br /&gt;
      &amp;lt;name&amp;gt;SetTarget&amp;lt;/name&amp;gt;&lt;br /&gt;
      &amp;lt;run&amp;gt;&lt;br /&gt;
        local lul_command = lul_prefix .. luup.devices[lul_device].id .. 'U\r'&lt;br /&gt;
        local lul_reverse = luup.variable_get(&amp;quot;urn:micasaverde-com:serviceId:HaDevice1&amp;quot;, &amp;quot;ReverseOnOff&amp;quot;, lul_device)&lt;br /&gt;
&lt;br /&gt;
        if (lul_settings.newTargetValue == &amp;quot;1&amp;quot; or (lul_settings.newTargetValue == &amp;quot;0&amp;quot; and lul_reverse == &amp;quot;1&amp;quot;)) then&lt;br /&gt;
          lul_command = lul_prefix .. luup.devices[lul_device].id .. 'D\r'&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        if (luup.io.write(lul_command) == false) then&lt;br /&gt;
          luup.log(&amp;quot;cannot send: &amp;quot; .. tostring(lul_command),1)&lt;br /&gt;
          luup.set_failure(true)&lt;br /&gt;
          return false&lt;br /&gt;
        end&lt;br /&gt;
      &amp;lt;/run&amp;gt;&lt;br /&gt;
    &amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/actionList&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This provides the implementation or the SetTarget UPnP action, which is what is sent when the user clicks 'on' or 'off' for a light switch, or 'open' or 'close' for blinds.  We store the command to send in the variable lul_command and put the 'local' keyword in front so the variable is only available while the 'SetTarget' action is running.  We also check the HADevice service's ReverseOnOff value.  As a convention in Luup, we created this as a common service that all home automation devices have, and the ReverseOnOff variable, if true, means reverse the usual on/off behavior, so on is off and off is on.  We did this because it's not uncommon for binary switches, particularly blinds, to be wired the wrong way, or for it to be subjective which position is on vs. off.  This way the user can add this variable for his configuration if the operation is backwards from what he would expect.  lu_SetCommFailure sets a &amp;quot;communication failure&amp;quot; flag for the device, which logs a critical error, and allows the user to see that the device is having problems.  Whenever the Luup engine reloads, such as clicking 'save', the flag is cleared again.&lt;br /&gt;
&lt;br /&gt;
Now when you click 'on' or 'off' for the blinds you'll see in the log it is sending the corresponding data to the blinds.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Debugging</id>
		<title>Luup Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Debugging"/>
				<updated>2012-05-08T15:16:15Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Third party tools */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
This document assumes you have already read [[Luup_Intro]] for a general introduction to Luup, [[Luup_Plugins]] to learn what goes into a plugin, and that you are creating the Luup plugin using either the web-based Luup plugin generator (coming soon) or are creating Luup's XML files by hand as described here: [[Luup_Plugins_ByHand]].  This document will help you debug the Lua code that you write and see what's going on with your plugins.&lt;br /&gt;
&lt;br /&gt;
To learn about Lua, see [http://www.lua.org/ lua.org] and the [http://www.lua.org/manual/5.1/ Lua reference manual] which lists all the functions and variables that are built into Lua.  &lt;br /&gt;
&lt;br /&gt;
The [http://lua-users.org/wiki/TutorialDirectory Lua Tutorial], on [http://Lua-Users.org lua-users.org], can also be of great help here.&lt;br /&gt;
&lt;br /&gt;
Additionally, the Luup engine provides a set of [[Luup_Lua_extensions|Extensions]] (variables and functions) you can call &lt;br /&gt;
within your Lua code.&lt;br /&gt;
&lt;br /&gt;
== Third party tools ==&lt;br /&gt;
&lt;br /&gt;
There are tools that will aid you in debugging your plugin:&lt;br /&gt;
&lt;br /&gt;
*'''putty''' If you are using Microsoft Windows you can download a utility, putty, to login to Vera's console here: [http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe]  You don't need to install putty.  Just put the .exe file on your desktop, run it, and in the host name type in the IP address of Vera and click 'open'.  At the ''&amp;lt;tt&amp;gt;login as:&amp;lt;/tt&amp;gt;'' prompt enter the username: ''&amp;lt;tt&amp;gt;root&amp;lt;/tt&amp;gt;'' and then when prompted enter the root password you setup.  If you don't see the root password or need help logging in see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
*'''DeviceSpy / Intel Tools for UPnP''' This is a set of tools for Microsoft Windows you can download here: [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology.zip]  We use the utility called ''DeviceSpy''&lt;br /&gt;
&lt;br /&gt;
== Luup logs ==&lt;br /&gt;
Vera is running Linux, and you can login to Vera's console to monitor the logs.  A special user, called ''root'', is used to login to Vera.  The password setup mechanism is different between Vera1 or a Vera2 models.&lt;br /&gt;
&lt;br /&gt;
=== Logging in on Vera1 ===&lt;br /&gt;
The ''root'' password must first be set in Vera's configuration menu's.  Do this by either going to Vera's Advanced, Net &amp;amp; Wi-fi tab and clicking 'Advanced configuration'&lt;br /&gt;
&lt;br /&gt;
Alternatively, at a Windows prompt, you can type ''telnet vera_ip'' (where vera_ip is the IP address of Vera).  If you login with telnet, type: ''passwd'' and press enter to set a root password.&lt;br /&gt;
&lt;br /&gt;
=== Logging in on Vera2 ===&lt;br /&gt;
The ''root'' password for a Vera2 box is printed on a label on the underside of the box.&lt;br /&gt;
&lt;br /&gt;
=== Getting around  ===&lt;br /&gt;
&lt;br /&gt;
If you have a Mac or Linux PC you can now login directly to Vera using ''ssh''. From the console type: ''ssh root@vera_ip'' (where vera_ip is the IP address of Vera). If you are using Windows, use putty as described above. &lt;br /&gt;
&lt;br /&gt;
When you are at the ''root@HomeControl:~#'' prompt type in: &lt;br /&gt;
&lt;br /&gt;
  cd /var/log/cmh''&lt;br /&gt;
&lt;br /&gt;
to go to the log directory. The command: &lt;br /&gt;
&lt;br /&gt;
  ls -lh&lt;br /&gt;
&lt;br /&gt;
lists all the log files. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;LuaUPnP.log&amp;lt;/tt&amp;gt; is the main log file. To see everything that is being logged by Luup in real time is called &amp;quot;tailing the log&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Do this by typing: &lt;br /&gt;
&lt;br /&gt;
  tail -f LuaUPnP.log&lt;br /&gt;
&lt;br /&gt;
To stop following the log press '''Ctrl+C'''. Press the up arrow to scroll through the recent commands to run them again by hitting enter, without retyping them. &lt;br /&gt;
&lt;br /&gt;
Note that Vera doesn't have a lot of memory for the logs. So regularly you will see the logs say 'Going to rotate logs' and then stop. This means the memory filled up so the logs are being removed. If the check box in Vera's Advanced, Logs page &amp;quot;Archive old logs on findvera (recommended)&amp;quot; is checked, the logs will be sent to Mi Casa Verde's server and archived for 7 days before purging. &lt;br /&gt;
&lt;br /&gt;
TODO: We'll add instructions for logging to a USB memory stick so you have more room. &lt;br /&gt;
&lt;br /&gt;
Each line starts with the log level and the date time, such as: &lt;br /&gt;
&lt;br /&gt;
  02      06/12/09 18:50:15.254  &lt;br /&gt;
&lt;br /&gt;
The first number, log level, has this meaning: &lt;br /&gt;
&lt;br /&gt;
*01 - Critical error. Something is wrong that shouldn't happen. &lt;br /&gt;
*02 - Warning. This is something to make note of, though it's not always a problem. &lt;br /&gt;
*03 - StartStop. These log messages indicate Luup engine is starting/stopping. This happens every time you save configuration changes. &lt;br /&gt;
*04 - Job. This relates to 'jobs'. &lt;br /&gt;
*05 - Home Automation. These logs are status messages from Home Automation devices. &lt;br /&gt;
*06 - Variable. A UPnP Variable has changed. &lt;br /&gt;
*07 - Event. An event is triggered. This is what you attach to a scene. &lt;br /&gt;
*08 - Action. A UPnP Action was received. &lt;br /&gt;
*09 - Enumeration. When the Luup engine starts this lists all the devices in the system. &lt;br /&gt;
*10 - General Status. There are lots of these messages to indicate something happening in the system. &lt;br /&gt;
*41 - Outgoing data. This is all data going to the external devices, such as the Z-Wave dongle, in their raw form. This is also true for your Luup plugins talking to the serial/network devices too. &lt;br /&gt;
*42 - Incoming data. (as above) &lt;br /&gt;
*50 - Lua code. When you log something in Lua code using the &amp;lt;tt&amp;gt;luup.log&amp;lt;/tt&amp;gt; function it has this log level. &lt;br /&gt;
*51 - Raw outgoing Serial data, from any Serial port attached to the Plugin. &lt;br /&gt;
*52 - Raw incoming Serial data, from any Serial port attached to the Plugin. &lt;br /&gt;
*200 - UPnP message. There are a huge amount of logs generated from the UPnP engine showing all activity.&lt;br /&gt;
&lt;br /&gt;
By default the Luup engine will skip logs with status 10 and 200 because they generate such a large amount of activity. Vera can actually be less reliable when 10 and 200 are activated because the logs grow so quickly sometimes that it is hard to archive them as fast as they come in. &lt;br /&gt;
&lt;br /&gt;
You can see what logs will shown by typing: &lt;br /&gt;
&lt;br /&gt;
  cat /etc/cmh/cmh.conf&lt;br /&gt;
&lt;br /&gt;
By default you will see: &lt;br /&gt;
&lt;br /&gt;
  LogLevels = 1,2,3,4,5,6,7,8,9,50&lt;br /&gt;
&lt;br /&gt;
meaning the Luup engine will log those log levels and ignore the rest. When you click 'Verbose logging' in Vera's web UI under setup, logs, you will see: &lt;br /&gt;
&lt;br /&gt;
  #LogLevels = 1,2,3,4,5,6,7,8,9,50&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;#&amp;lt;/tt&amp;gt; in front means the log levels are ignored and all logs are stored, except UPnP. If you really want to see the UPnP messages, which will fill up the memory very fast, you can type &lt;br /&gt;
&lt;br /&gt;
  vi /etc/cmh/cmh.conf&lt;br /&gt;
&lt;br /&gt;
and move the cursor on top of the 0 in LogUPnP = 0. Then press ''r1'' to replace the 0 with a 1, and then type '':wq'' to write the changes and quit. These somewhat arcane commands are part of Linux's default text editor, vi. After you make a change, you will want to restart the Luup engine. Do this by clicking the 'save' button. Because you normally just want full logging temporarily, Luup will automatically revert to the default log levels after 4 hours unless you check 'Lock log levels' in Vera's Advanced, Log page. &lt;br /&gt;
&lt;br /&gt;
To make sense of what's in the logs it's best to use grep and 'regular expressions'. If you're a true uber geek this is the greatest joy. If you're a mere mortal, it's best to just stick to some examples. In regular expressions the symbol ^ means 'show me lines that start with' and the symbol \| means 'or'. So here are some samples: &lt;br /&gt;
&lt;br /&gt;
Show me everything in the log that is a 'critical error': &lt;br /&gt;
&lt;br /&gt;
  grep '^01' LuaUPnP.log&lt;br /&gt;
&lt;br /&gt;
I enabled Verbose logging, so incoming/outgoing data is logged, show me that plus any normal log messages (0-9) plus any log messages in my Lua code: &lt;br /&gt;
&lt;br /&gt;
  grep '^0\|^4\|^5' LuaUPnP.log&lt;br /&gt;
&lt;br /&gt;
(meaning any line that starts with 0, which 0-9, or 4, which is 40 and 41, or 5, which is 50. &lt;br /&gt;
&lt;br /&gt;
I want the same data, but I want to follow the logs in real time with the same filter: &lt;br /&gt;
&lt;br /&gt;
  tail -f LuaUPnP.log | grep '^0\|^4\|^5'&lt;br /&gt;
&lt;br /&gt;
You can also put in the 'grep' strings that you want to match. Let's say you see in the logs that every time a job status changes it logs using log level 10 (status) some line that includes the string: 'Job::m_eJobStatus'. You want to follow the logs and show just Lua logs, critical errors, and job status changes: &lt;br /&gt;
&lt;br /&gt;
  tail -f LuaUPnP.log | grep '^5\|^01\|Job::m_eJobStatus'&lt;br /&gt;
&lt;br /&gt;
When you are writing your Lua code, include copious logging with &amp;lt;tt&amp;gt;luup.log&amp;lt;/tt&amp;gt; (see [[Luup Lua extensions#function:_log|Luup_Lua_extensions log function]]) to see what's happening in your Lua code.&lt;br /&gt;
&lt;br /&gt;
==Debug in small chunks without restarting each time==&lt;br /&gt;
&lt;br /&gt;
If you are adding code for an action, it takes time to upload your files and initiate the action.  So it's best to debug the Lua code in tiny bite sized pieces first to be sure the syntax and basic operation is ok.&lt;br /&gt;
&lt;br /&gt;
In Vera's web ui choose Devices, Luup plugins and click 'Test Lua UPnP code'.  For the device number put in the number of the device you are debugging, which is shown when you click the + button next to the device.  Or, if your Lua code isn't going to be calling any of the functions and variables you created in that device, you can just put in a device number of 0, which means this snippet of code runs by itself.  If you put in a valid device number for a Luup plugin, it runs in the context of that device meaning it can call the other functions and variables in the plugin.&lt;br /&gt;
&lt;br /&gt;
Put your small chunk of code in the input box and click 'go' to run it.  Be sure the code outputs something to the log with &amp;lt;tt&amp;gt;luup.log&amp;lt;/tt&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
In another console or putty window you can be following the logs with:&lt;br /&gt;
&lt;br /&gt;
  tail -f LuaUPnP.log | grep '^01\|^5'&lt;br /&gt;
&lt;br /&gt;
Always log critical errors, &amp;lt;tt&amp;gt;01&amp;lt;/tt&amp;gt;, because that way if your Lua code won't run due to a syntax error you will see the log entry.&lt;br /&gt;
&lt;br /&gt;
In the real implementation your Lua code will probably be passed variables.  For example, if the Lua code being run is in response to an action, it will be passed as a variable the arguments to the UPnP action.  To test your small blocks of code with this you can simply add the same variable names and hardcode some test variables.  The list of variables that are passed to your Lua code are documents here: [[Luup_Declarations]].  You can also see the complete Lua code that the Luup engine has generated including the function declarations with the &amp;lt;tt&amp;gt;lu_lua&amp;lt;/tt&amp;gt; (See [[Luup_Requests#lu_lua|Luup_Requests lu_lua]]) request on the URL.&lt;br /&gt;
&lt;br /&gt;
For example, I will view the complete Lua code for device #8: &lt;br /&gt;
&lt;br /&gt;
  http://vera_ip:49451/data_request?id=lu_lua&amp;amp;DeviceNum=8&lt;br /&gt;
&lt;br /&gt;
and I can see that the Lua code I put in my 'run' XML tag in the implementation file for the &amp;lt;tt&amp;gt;SetTarget&amp;lt;/tt&amp;gt; action looks like this is within this function declaration:&lt;br /&gt;
&lt;br /&gt;
  function SetTarget_run(lul_device,lul_settings)&lt;br /&gt;
&lt;br /&gt;
As explained in [[Luup_Declarations]] the &amp;lt;tt&amp;gt;lul_device&amp;lt;/tt&amp;gt; will the device number that is receiving the command.  So if I want to test some Lua code that I will put inside a 'run' tag for the &amp;lt;tt&amp;gt;SetTarget&amp;lt;/tt&amp;gt; action, which logs the device that received the UPnP Action (we'll use 10) and the argument &amp;lt;tt&amp;gt;newTargetValue&amp;lt;/tt&amp;gt; which indicates if the device is being turned on or off, then I would put in the test code:&lt;br /&gt;
&lt;br /&gt;
  lul_device=10&lt;br /&gt;
  lul_settings['newTargetValue']=1&lt;br /&gt;
  luup.log(&amp;quot;Got a SetTarget action for device &amp;quot; .. lul_device .. &amp;quot; to turn on/off: &amp;quot; .. lul_settings['newTargetValue'])&lt;br /&gt;
&lt;br /&gt;
now when you click 'go' see what goes in the Log.  If your log entry is ok, copy the &amp;lt;tt&amp;gt;luup.log&amp;lt;/tt&amp;gt; line from this test code, without the &amp;lt;tt&amp;gt;lul_device=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;lul_settings=&amp;lt;/tt&amp;gt; lines, into the actual implementation and you know that it will work when the real UPnP action is called and the Luup engine passes the actual &amp;lt;tt&amp;gt;lul_device&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;lul_settings&amp;lt;/tt&amp;gt; to your Lua code.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Scenes_Events</id>
		<title>Luup Scenes Events</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Scenes_Events"/>
				<updated>2012-05-08T15:15:34Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Walk-through #1 -- At 12 noon, turn off the interior lights if the temperature is over 80 degrees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Adding Lua code to scenes and events  ==&lt;br /&gt;
&lt;br /&gt;
[[Image:SceneFlowchart.png]] &lt;br /&gt;
&lt;br /&gt;
You can add Lua script to scenes and events for simple tasks, like making a scene or event conditional. Conditional meaning &amp;quot;do something only '''if''' some condition is met&amp;quot;, such as attaching a condition to your &amp;quot;Come Home&amp;quot; scene so it is only run '''if''' the temperature is over 70 degrees. Basic conditional expressions are easy, and, if that's all you're looking to do, skip to the walk-through below. &lt;br /&gt;
&lt;br /&gt;
If you're more technically inclined you can also do very advanced things too. For an overview of all the advanced things you can do with Vera's Luup engine, and how scenes and events fit in, see the [[Luup Intro]] page. &lt;br /&gt;
&lt;br /&gt;
To add Lua code to a scene, create the [[Scenes]] and click 'Luup scene'. Fill in your Lua code in the input box. To do a simple condition, see the sample below. Or if you want to do advanced scripting you can use any [[http://lua.org Lua]] commands as described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]] as well as the variables and functions that the Luup engine adds to Lua documented here: [[Luup Lua extensions]]. The Lua code will be run every time the scene is activated either by the user or a scene or a timer. The Lua code is run before the commands that you included in the scene. If your Lua code ends with this: &amp;quot;return false&amp;quot; then the commands in the scene will not be run. &lt;br /&gt;
&lt;br /&gt;
You can also add Lua code to an event by clicking 'Luup event'. Since events are attached to scenes anyway, there is usually little difference between adding the code to an event, or to the scene the event is part of. If the Lua code in an event returns false, then the event is aborted, meaning the scene that the event is attached to will not be triggered by the event. The main reason for attaching Lua code to an event is if you have multiple events to a scene. For example, you may have a scene called &amp;quot;Turn lights on in hallway&amp;quot; which is triggered by 2 events: 1) The front door opens, and 2) the motion sensor in the hallway is tripped. Perhaps whenever the front door opens you always want the scene to be activated, but you only want the motion sensor to activate the scene before 10:00. In this case, you would add Lua code to the motion sensor's event which does something like (pseudo-code): &amp;quot;if time&amp;amp;gt;10:00 return false&amp;quot;. That way the event from the motion sensor will be aborted if it's after 10:00, but the event from the front door will always activate the scene regardless. &lt;br /&gt;
&lt;br /&gt;
When you edit the Lua code in a scene or event you must click 'Save' before the code is saved. Then you can activate the scene or trigger the event to see what happens when your code is run. If you're doing some advanced scripting that you'll need to debug this can be tedious, but there are easy ways to test your Lua script immediately without saving first as explained in [[Lua Debugging]]. &lt;br /&gt;
&lt;br /&gt;
If you're doing advanced Lua scripting, you should note that all the Lua code in your scenes and events run in a single Lua instance, which is separate from any Lua plugins. This means if you set a global variable in one scene, or create a function inside the Lua code in a scene, then in another scene's Lua code you can use that global variable or call that function. You do not need to worry about conflicting with a Luup plugin, though, since they have their own Lua instance, meaning they have their own global variables and functions. &lt;br /&gt;
&lt;br /&gt;
== Walk-through #1 -- At 12 noon, turn off the interior lights if the temperature is over 80 degrees  ==&lt;br /&gt;
&lt;br /&gt;
Before you start, in Vera's setup interface go to 'Devices' and click the '+' button next to the thermostat. Make note of the Device #. &lt;br /&gt;
&lt;br /&gt;
In this walkthrough we'll assume it's Device #3, but use the actual device number of''your'' thermostat. Next, visit [[Luup Variables]] to get a list of all the variables for devices. A variable is a piece of information about the current state of a device, such as whether it's on or off, it's current temperature, etc. &lt;br /&gt;
&lt;br /&gt;
Look down at ''Thermostat'', and copy the name of the service/variable which corresponds to the current temperature, namely. In this case, it's &lt;br /&gt;
&lt;br /&gt;
  urn:upnp-org:serviceId:TemperatureSensor1 CurrentTemperature&lt;br /&gt;
&lt;br /&gt;
Notice that it states the &amp;lt;tt&amp;gt;CurrentTemperature&amp;lt;/tt&amp;gt; is in Celsius. So type in &amp;quot;80 degrees Fahrenheit to Celsius&amp;quot; in Google and you'll see that it's 26.6 degrees Celsius. &lt;br /&gt;
&lt;br /&gt;
Now, the first step is to create the scene that turns off the lights. In Vera's setup interface, click 'Scenes', and click 'Add Scene' to add a new scene to one of the rooms. It's not important which room you choose. Scenes are categorized in rooms just to help you keep track of them if you have a lot of scenes. You can also put the scene in 'Global Scenes', or, you can create dummy rooms on the 'Rooms' tab if you want to have more &amp;quot;rooms&amp;quot; to organize your scenes with. After you click 'Add Scene', type in a description to remember your scene by, such as &amp;quot;Lights off 12:00 if 80&amp;quot;. Under the 'Commands' area you'll see all the rooms. Click '+' next to the rooms that have lights you want to control, and choose &amp;quot;Off&amp;quot; in the pull-down. At this point, you have a normal scene, and, if you were to save your changes now, whenever you click the scene on the dashboard or on a remote control, the lights should turn off. &lt;br /&gt;
&lt;br /&gt;
Second, next to the scene's description click 'add timer'. You can give the timer a description too so that if you have multiple timers you can see in the logs which one is activating the scene. Choose &amp;quot;Day of week based&amp;quot;. If you want this scene to only run on certain days of the week, just check off which days you want this scene to run on. Otherwise, you can leave them all unchecked (or check them all) to do it every day. Leave the pull-down at &amp;quot;a certain time of day&amp;quot;, and choose 12&amp;amp;nbsp;: 00&amp;amp;nbsp;: 00 from the pull-downs. At this point, if you were to save your changes, the lights would turn off automatically at 12 noon. &lt;br /&gt;
&lt;br /&gt;
Third, the last step is to add the condition. To the right of the scene's description you'll see the button &amp;quot;Luup Scene&amp;quot;. Click it and in the code box, copy and paste the following: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local lul_temp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:TemperatureSensor1&amp;quot;,&amp;quot;CurrentTemperature&amp;quot;, 3)&lt;br /&gt;
  if (tonumber(lul_temp) &amp;lt; 26.6) then&lt;br /&gt;
    return false&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Don't forget to change the &amp;quot;3&amp;quot; to whatever is the actual device number of your thermostat. Assign the result of &amp;lt;tt&amp;gt;luup.variable_get&amp;lt;/tt&amp;gt; to a variable first, rather than putting it directly in the &amp;lt;tt&amp;gt;tonumber()&amp;lt;/tt&amp;gt;, because &amp;lt;tt&amp;gt;luup.variable_get&amp;lt;/tt&amp;gt; actually returns 2 values: the value of the variable, and the time when the variable was modified. The '&amp;lt;tt&amp;gt;tonumber&amp;lt;/tt&amp;gt;' is needed because all of a device's variables are stored as plain text--not numbers--so if you want to do arithmetic or numeric comparison of a variable, you need to put &amp;lt;tt&amp;gt;tonumber()&amp;lt;/tt&amp;gt; around &amp;lt;tt&amp;gt;luup.variable_get&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;luup.variable_get&amp;lt;/tt&amp;gt; is documented in [[Luup Lua extensions]]. &lt;br /&gt;
&lt;br /&gt;
Now click 'Update', and then click 'Save' to save everything. The &amp;quot;return false&amp;quot; means &amp;quot;don't run this scene&amp;quot;. So if the current temperature is &amp;amp;lt;26.6, the scene will be aborted and won't run. The timer will make it trigger every day at 12 noon. &lt;br /&gt;
&lt;br /&gt;
To test it, you can click the scene button on the dashboard. The lights will turn off only if the temperature is over 80 degrees. If it's less than 80 degrees, the scene won't do anything. Since this scene is something that happens automatically and you probably won't execute manually, you can go to the scene again and check the &amp;quot;Hidden&amp;quot; box so the scene doesn't show up on&amp;amp;nbsp;Vera's 'Dashboard' and on your remote controls, like the iPhone. If you want to have a scene that turns off the lights which you can run whenever you want from 'Dashboard''or your remote control, you should create another scene that has the same commands and simply don't add the timers and Luup conditions, and don't check the &amp;quot;Hidden&amp;quot; box. '' &lt;br /&gt;
&lt;br /&gt;
You can substitute other service/variables and device ID's to make other types of conditions. The &amp;quot;if&amp;quot; statement above also supports nesting with ( and ), as well as the keywords 'and' and 'or'. So the following means the scene would abort if the temperature is &amp;amp;lt;26.6 and &amp;amp;gt;25, unless it's &amp;amp;lt;23: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local lul_temp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:TemperatureSensor1&amp;quot;,&amp;quot;CurrentTemperature&amp;quot;, 3)&lt;br /&gt;
  if ((tonumber(lul_temp) &amp;lt; 26.6&lt;br /&gt;
    and tonumber(lul_temp) &amp;gt; 25)&lt;br /&gt;
    or tonumber(lul_temp) &amp;lt; 23) then&lt;br /&gt;
      return false&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
If the scene doesn't run, it's possible&amp;amp;nbsp;there is&amp;amp;nbsp;a syntax error. The easiest way to test this is to copy the Lua code from the scene, then go to Devices, Luup Plugins, and &amp;quot;Test Luup code&amp;quot;. Paste the code in the box and click 'go'. If the info box above the 'go' button has a check and says &amp;quot;Message sent successful&amp;quot;, your code is okay. If there's an error, it says: &amp;quot;Code failed&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
To see if that's true, use putty, or telnet or ssh to log-in to Vera, as explained in detail in [[Logon_Vera_SSH]] and [[Lua Debugging]], and type: &lt;br /&gt;
&lt;br /&gt;
   cd /var/log/cmh&lt;br /&gt;
 tail -f LuaUPnP.log | grep '^01'&lt;br /&gt;
&lt;br /&gt;
Now click 'Save' in Vera's setup page, even if it's gray, as that will cause Vera to restart the Luup engine and log any syntax errors. See: [[Lua Debugging]] for in-depth details on how to debug.&lt;br /&gt;
&lt;br /&gt;
== Walk-through #2 -- Only run the scene during the daytime  ==&lt;br /&gt;
&lt;br /&gt;
In the Luup tab for the scene paste this: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  return luup.is_night() == false&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
That works because if the return is 'true' the scene runs, and if it's 'false' it doesn't. So during the daytime the expression is true. Or, an alternative long form: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  if (luup.is_night()) then&lt;br /&gt;
     return false&lt;br /&gt;
  else&lt;br /&gt;
     return true&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Samples  ==&lt;br /&gt;
&lt;br /&gt;
This page is a wiki which anyone can edit. If you have some Lua code you think other users might find useful, feel free to add it here. &lt;br /&gt;
&lt;br /&gt;
=== Lighting and Switch Actions  ===&lt;br /&gt;
&lt;br /&gt;
Did you see the sample here already: http://wiki.micasaverde.com/index.php/Luup_Scenes_Events &lt;br /&gt;
&lt;br /&gt;
==== Turn an appliance switch or a Danfoss thermostat on for device #5  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;, &amp;quot;SetTarget&amp;quot;, {newTargetValue = &amp;quot;1&amp;quot;}, 5)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Turn an appliance switch or a Danfoss thermostat off  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;, &amp;quot;SetTarget&amp;quot;, {newTargetValue = &amp;quot;0&amp;quot;}, 5)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Do something if switch device #5 is on  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local lul_tmp = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;, &amp;quot;Status&amp;quot;, 5)&lt;br /&gt;
  if (lul_tmp == &amp;quot;1&amp;quot;) then&lt;br /&gt;
     --something to do goes here&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Dim switch #6 to 30%  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;SetLoadLevelTarget&amp;quot;, {newLoadlevelTarget = &amp;quot;30&amp;quot;}, 6)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Blinking lights  ====&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5127.0 &lt;br /&gt;
&lt;br /&gt;
=== Motion Sensor Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== Arm motion sensor #7  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;, &amp;quot;Armed&amp;quot;, &amp;quot;1&amp;quot;, 7)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Disarm motion sensor #7  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.variable_set(&amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;, &amp;quot;Armed&amp;quot;, &amp;quot;0&amp;quot;, 7)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Note, arming and disarming isn't a concept within UPnP or Z-Wave. It's just a flag that the Luup engine uses, and is stored in a variable we created called &amp;quot;Armed&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
=== Scene Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== Run Scene #5  ====&lt;br /&gt;
&lt;br /&gt;
Thanks &amp;quot;denix&amp;quot; on the forum for the correct syntax. &amp;quot;Actually, the 4th parameter IS required, but it's not used. Otherwise the command fails with an error message&amp;quot; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;, &amp;quot;RunScene&amp;quot;, {SceneNum = &amp;quot;5&amp;quot;}, 0)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
In this case we left the device number off (the 4th parameter to &amp;lt;tt&amp;gt;luup.call_action&amp;lt;/tt&amp;gt;), because the &amp;quot;&amp;lt;tt&amp;gt;RunScene&amp;lt;/tt&amp;gt;&amp;quot; action is handled by the Luup engine itself--not by some device within Z-Wave, etc. &lt;br /&gt;
&lt;br /&gt;
However, normally you don't need to &amp;lt;tt&amp;gt;luup.call_action&amp;lt;/tt&amp;gt; in Lua code. Rather, whatever actions, or commands, you want to run, you put into the scene itself, and the only Lua code is to simply check if some condition is true and abort the scene if the condition isn't met. &lt;br /&gt;
&lt;br /&gt;
=== Thermostat Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== Change the Temperature on Thermostat (Cool) device #19  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&amp;quot;,&lt;br /&gt;
                   &amp;quot;SetCurrentSetpoint&amp;quot;, {NewCurrentSetpoint = &amp;quot;68&amp;quot;},&lt;br /&gt;
                   19)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Change the Temperature on a Thermostat (Heat) device #19  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  luup.call_action(&amp;quot;urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&amp;quot;,&lt;br /&gt;
                   &amp;quot;SetCurrentSetpoint&amp;quot;, {NewCurrentSetpoint = &amp;quot;68&amp;quot;},&lt;br /&gt;
                   19)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Change the Thermostat Operating mode device #19  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.call_action(&amp;quot;urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;quot;,&lt;br /&gt;
                 &amp;quot;SetModeTarget&amp;quot;, {NewModeTarget = &amp;quot;Off&amp;quot;},&lt;br /&gt;
                 19)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== Camera Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== 'Privacy' mode for Foscam FI8908[w]  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local IP_address = '&amp;lt;IP address of camera&amp;gt;'&lt;br /&gt;
  local username = '&amp;lt;username&amp;gt;'&lt;br /&gt;
  local password = '&amp;lt;password&amp;gt;'&lt;br /&gt;
  local timeout  = 5&lt;br /&gt;
 &lt;br /&gt;
  function move_up()&lt;br /&gt;
    luup.inet.wget('http://' .. IP_address .. '/decoder_control.cgi?command=0', timeout, username, password)&lt;br /&gt;
  end&lt;br /&gt;
 &lt;br /&gt;
  -- center the camera; takes some time, so we have to wait 2 minutes for the command to complete&lt;br /&gt;
 &lt;br /&gt;
  luup.inet.wget('http://' .. IP_address .. '/decoder_control.cgi?command=25', timeout, username, password)&lt;br /&gt;
 &lt;br /&gt;
  luup.call_delay('move_up', 120)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== Misc Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== Playing an announcement  ====&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5466.msg36405#msg36405 &lt;br /&gt;
&lt;br /&gt;
=== Calculate sunrise and sunset  ===&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2073.msg8132#msg8132 &lt;br /&gt;
&lt;br /&gt;
... or use DAD: http://forum.micasaverde.com/index.php?topic=5466.0 &lt;br /&gt;
&lt;br /&gt;
=== Access the web  ===&lt;br /&gt;
&lt;br /&gt;
==== Invoke HTTP URL with &amp;lt;tt&amp;gt;GET&amp;lt;/tt&amp;gt; request (Method 1)  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  -- 5 Second timeout&lt;br /&gt;
  local status, result = luup.inet.wget(&amp;quot;http://www.yahoo.com&amp;quot;, 5)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Invoke HTTP URL with &amp;lt;tt&amp;gt;GET&amp;lt;/tt&amp;gt; request (Method 2)  ====&lt;br /&gt;
&lt;br /&gt;
Based on code by Jim/jgc94131 &amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  require('ltn12')&lt;br /&gt;
  local http = require('socket.http')&lt;br /&gt;
&lt;br /&gt;
  -- 5 Second timeout&lt;br /&gt;
  socket.http.TIMEOUT = 5&lt;br /&gt;
&lt;br /&gt;
  local response_body = {}&lt;br /&gt;
  local request_body = ''&lt;br /&gt;
&lt;br /&gt;
  local r, c, h = socket.http.request{&lt;br /&gt;
    url = 'http://website/page?parameter1=value&amp;amp;parameter2=value',&lt;br /&gt;
    method = &amp;quot;GET&amp;quot;,&lt;br /&gt;
    port = 80,&lt;br /&gt;
    headers = {&lt;br /&gt;
      [&amp;quot;Content-Length&amp;quot;] = string.len(request_body),&lt;br /&gt;
      [&amp;quot;Content-Type&amp;quot;] = &amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    source = ltn12.source.string(request_body),&lt;br /&gt;
    sink = ltn12.sink.table(response_body)&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== Invoke HTTP URL with &amp;lt;tt&amp;gt;POST&amp;lt;/tt&amp;gt; request (Method 3)  ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local http = require(&amp;quot;socket.http&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  -- 5 Second timeout&lt;br /&gt;
  http.TIMEOUT = 5&lt;br /&gt;
&lt;br /&gt;
  -- The return parameters are in a different order from luup.inet.wget(...)&lt;br /&gt;
  result, status = http.request(&amp;quot;http://192.168.0.113/runprocess.htm&amp;quot;, &amp;quot;run=run&amp;quot;)    &lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== Access the current time  ===&lt;br /&gt;
&lt;br /&gt;
The Lua function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  os.date (format, time)&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
converts a time value `time` into a human readable date/time string, according to `format`. If you leave out the optional `time` parameter, it defaults to current time. The `format` parameter defaults to a fairly complete format. If you specify '*t' as the format, it will return a table instead of a formatted string. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  t = os.date('*t')&lt;br /&gt;
  t =&amp;gt; {year=2010, month=2, day=19, yday=50, wday=6, hour=22, min=45, sec=45, isdst=false}&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The fields are year, month, day of month, day of year, day of week, hour in 24 hour clock, minutes, seconds and if it's Daylight Savings Time. &lt;br /&gt;
&lt;br /&gt;
Current hour: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  os.date('*t').hour&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Current minute: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  os.date('*t').min&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Current second: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  os.date('*t').sec&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Do something between 16:00 and 21:15: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
  local t = os.date('*t')&lt;br /&gt;
  local current_second = t.hour * 3600 + t.min * 60 + t.sec   -- number of seconds since midnight&lt;br /&gt;
  local min_time_in_seconds = 16 * 3600 +  0 * 60             -- 16:00&lt;br /&gt;
  local max_time_in_seconds = 21 * 3600 + 15 * 60             -- 21:15&lt;br /&gt;
 &lt;br /&gt;
  if (current_second &amp;gt; min_time_in_seconds) and (current_second &amp;lt; max_time_in_seconds) then&lt;br /&gt;
    -- do something&lt;br /&gt;
  else&lt;br /&gt;
    return false&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2015.0 and http://www.lua.org/manual/5.1/manual.html#5.8. &lt;br /&gt;
&lt;br /&gt;
=== Set Z-Wave parameters  ===&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=1937.msg7803#msg7803 &lt;br /&gt;
&lt;br /&gt;
=== a scene if the temperature is outside of a range  ===&lt;br /&gt;
&lt;br /&gt;
add snippets here... &lt;br /&gt;
&lt;br /&gt;
=== Reload Luup at 3 AM every day  ===&lt;br /&gt;
&lt;br /&gt;
1. Create a scene and set it to run daily at 3 AM. &lt;br /&gt;
&lt;br /&gt;
2. Add this code in the '''Luup code''' box: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;, &amp;quot;Reload&amp;quot;, {}, 0)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
3. Save.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2012-05-08T15:14:45Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Not getting status changes with door locks, or door locks out of sync */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.conf (or zwave_products_user.xml?) in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password see [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2012-05-08T15:14:17Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Not getting status changes with door locks, or door locks out of sync */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.conf (or zwave_products_user.xml?) in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F|Logon # Can't find the root password?]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2012-05-08T15:13:41Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Not getting status changes with door locks, or door locks out of sync */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.conf (or zwave_products_user.xml?) in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password [[Logon_Vera_SSH#Can.27t_find_the_root_password.3F]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Logon_Vera_SSH</id>
		<title>Logon Vera SSH</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Logon_Vera_SSH"/>
				<updated>2012-05-08T15:12:35Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:User Instructions]]&lt;br /&gt;
[[Category:How To]]&lt;br /&gt;
'''HOWTO  log on to your Vera using SSH.'''&lt;br /&gt;
&lt;br /&gt;
==Prerequisites==&lt;br /&gt;
* Vera 1-3 hardware&lt;br /&gt;
* For Windows based clients, an open-source SSH application to access your Vera, for instance PuTTY which can be found here:  [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html]&lt;br /&gt;
* For MAC clients you could use &amp;quot;Rbrowser&amp;quot; to be found here [http://www.openssh.com] or here [http://www.rbrowser.com]&amp;lt;br /&amp;gt;&lt;br /&gt;
* Linux based clients have built-in SSH support. &lt;br /&gt;
* Root password, to be found at the bottom of your Vera (also your initial WiFi security key)&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
For many operations you need access to the shell of your Vera. For this reason Vera supports SSH (Secure SHell) on port 22.&amp;lt;br /&amp;gt;&lt;br /&gt;
Getting access to your Vera is not something that is easy at first.&amp;lt;br /&amp;gt;&lt;br /&gt;
Therefore you can follow these instructions in support of other How To's to get root access to your Vera's shell.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Instructions==&lt;br /&gt;
===Windows===&lt;br /&gt;
*After you have downloaded PuTTY, run it directly.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get shell acces to your Vera do this;&amp;lt;br /&amp;gt;&lt;br /&gt;
1. Under &amp;lt;Host Name&amp;gt; type the IP address of your Vera (for example: 192.168.1.24), leave Port number 22 alone, if needed, change connection type to SSH (default) and click &amp;lt;Open&amp;gt;.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. At Login type:&amp;lt;br /&amp;gt;&lt;br /&gt;
 ''root''&lt;br /&gt;
hit &amp;lt;Enter&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The password you need is located on the label under your Vera unit assigned to &amp;quot;WiFI Pass&amp;quot;.&amp;lt;br /&amp;gt;&lt;br /&gt;
3. Type the password and hit &amp;lt;Enter&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mac &amp;amp; Linux===&lt;br /&gt;
1. Open a &amp;quot;Terminal&amp;quot;.&amp;lt;br /&amp;gt;&lt;br /&gt;
2. type:      &lt;br /&gt;
 ''ssh root@192.168.1.24''&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
You now should have access to your Vera's Root directory and it should display something like this:&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''BusyBox v1.15.3 (2010-06-10 18:19:49 PDT) built-in shell (ash''')&amp;lt;br /&amp;gt;&lt;br /&gt;
 '''Enter 'help' for a list of built-in commands.'''&lt;br /&gt;
 ---------------------------------------------------&lt;br /&gt;
  ***      MiOS LTD. ( www.mios.com )        ***&lt;br /&gt;
  ***                                        ***&lt;br /&gt;
  ***               WARNING :                ***&lt;br /&gt;
  *** Any changes made to the system without ***&lt;br /&gt;
  *** guidance from MiOS support will VOID   ***&lt;br /&gt;
  *** your future Support requests           ***&lt;br /&gt;
 ---------------------------------------------------&lt;br /&gt;
 '''root@MiOS_xxxxx:~#'''&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
(the xxxxx will be your Vera's name)&amp;lt;br /&amp;gt;&lt;br /&gt;
From here you can use any shell command provided in other How To's or forum items.&lt;br /&gt;
&lt;br /&gt;
==Can't find the root password?==&lt;br /&gt;
&lt;br /&gt;
On Vera Lite's, the root password isn't printed on the bottom.  So you need to access to the 'Tech Support' settings.  Depending on your UI version, this is either under the Advanced tab, the Settings tab, or the Account tab.  There will be an 'enable' button.  Click that to turn on the tech support service.  You will see a message like this:&lt;br /&gt;
&lt;br /&gt;
Tech support full control enabled, access code 3000000-436969&lt;br /&gt;
&lt;br /&gt;
The first number is your serial number, which is always printed on the bottom.  The second number is a temporary password created for a user called &amp;quot;remote&amp;quot;.  So, follow the same login instructions, but, instead of typing root for the login, type remote.  And instead of using the normal password, use that temporary password, 436969 in this case.  Once you have gotten in to the console, you can see the actual root password using this command: nvram show | grep pass&lt;br /&gt;
&lt;br /&gt;
You'll see something like this:&lt;br /&gt;
&lt;br /&gt;
root@MiOS_30000000:~# nvram show | grep pass&lt;br /&gt;
vera_wifipass=shade83forest&lt;br /&gt;
&lt;br /&gt;
So in this case, shade83forest, is the actual root password.  Write it down, and from now on login as 'root' as explained earlier, and use that password.  The temporary password for the remote user will only be valid for 24 hours or until you click 'Disable it' on the tech support page.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
please find more info here;&amp;lt;br /&amp;gt;&lt;br /&gt;
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html&amp;lt;br /&amp;gt;&lt;br /&gt;
http://www.openssh.com/&amp;lt;br /&amp;gt;&lt;br /&gt;
http://www.rbrowser.com/&amp;lt;br /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/ZWave_Debugging</id>
		<title>ZWave Debugging</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/ZWave_Debugging"/>
				<updated>2012-05-08T15:05:10Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* Not getting status changes with door locks, or door locks out of sync */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
== Custom device types or names based on Z-Wave ID's  ==&lt;br /&gt;
&lt;br /&gt;
In the configuration directory (normally /etc/cmh) is a file called zwave_products_sys.xml.  This contains a list of hardcoded settings for various ZWave devices.  The file is a series of values separated by tabs, with one entry on each line.  The format is:&lt;br /&gt;
&lt;br /&gt;
Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID, Devicefilename, ZWaveClass, Default name, Custom variables&lt;br /&gt;
&lt;br /&gt;
When a Z-Wave device is added it is compared against this file.  If the device's manufacturer ID, Basic ZWave device class, Generic device class, Specific device class, Product Type and Product ID match what's in the file, then rather than using the default device information, the device will use the UPnP XML device file in Devicefilename, and the ZWave class ZWaveClass, and will have the Default name, and the UPnP variables in &amp;quot;Custom variables&amp;quot;.  If any of Manufacturer, Basic, Generic, Specific, ChildNumber, ProductType, ProductID are not specified, it's considered a match.  If any of Devicefilename, ZWaveClass, Default name, Custom variables are not specified, the default values are used.  ChildNumber is when there's a multi-channel or multi-instance, this is what the child device will use.&lt;br /&gt;
&lt;br /&gt;
For example, for the Express controls 3-in-1 sensor which has manufacturer 001E and Product Type/ID are 2 and 1, the 3 embedded children are forced to be a motion sensor, light sensor, temperature sensor.&lt;br /&gt;
&lt;br /&gt;
 001E				1	2	1	D_MotionSensor1.xml	&lt;br /&gt;
 001E				2	2	1	D_LightSensor1.xml	&lt;br /&gt;
 001E				3	2	1	D_TemperatureSensor1.xml	&lt;br /&gt;
&lt;br /&gt;
zwave_products_sys.xml is distributed with each MIOS release, so any changes you make to it are lost on upgrade.  However, you can add your own rows in the file: zwave_products_user.conf (or zwave_products_user.xml?) in the same folder with the same format.  Those will be saved when you upgrade.&lt;br /&gt;
&lt;br /&gt;
To get the source values (manufacturer id, product type, etc.) grep for UpdateNode in LuaUPnP.log.&lt;br /&gt;
&lt;br /&gt;
== Easy Z-Wave Debugging  ==&lt;br /&gt;
&lt;br /&gt;
== Z-Wave specifics  ==&lt;br /&gt;
&lt;br /&gt;
Vera maps the command class BASIC to COMMAND_CLASS_SENSOR_BINARY, and responds to BASIC_GET or SENSOR_BINARY_GET with a _REPORT that has a value of 1 if Vera is running (ie it's always 1). &lt;br /&gt;
&lt;br /&gt;
== Advanced debugging for developers  ==&lt;br /&gt;
&lt;br /&gt;
Here are some hints for debugging Z-Wave protocol issues. You can access Vera by telnet, or if you already set a password, by ssh. &lt;br /&gt;
&lt;br /&gt;
First, be sure you check the box &amp;quot;verbose logs&amp;quot; under 'Advanced', 'Logging', or, from a console run /usr/bin/VerboseLogging.sh enable. &lt;br /&gt;
&lt;br /&gt;
The logs are in the directory /var/log/cmh. The first 2 digits are the 'log level'. The file: DCERouter.log contains the logging information from the core message router. The file: x-ZWave.log (where x is usually 9) contains all the logs from the Z-Wave module. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Log levels for data sent to the Z-Wave dongle&amp;lt;/u&amp;gt;:&amp;lt;br&amp;gt; 01 = critical errors&amp;lt;br&amp;gt; 02 = warnings&amp;lt;br&amp;gt; 04 = jobs &amp;lt;br&amp;gt;05 = warnings&amp;lt;br&amp;gt; 06 = variables (which indicates state changes)&amp;lt;br&amp;gt;07 = events&amp;lt;br&amp;gt;08 = commands&amp;lt;br&amp;gt;10 = status messages&amp;lt;br&amp;gt; 41 = data sent to the Z-Wave dongle&amp;lt;br&amp;gt;42 = data received from the Z-Wave dongle&amp;lt;br&amp;gt; 50 = luup log &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For commands run in a scene, the logs won't be getting data from the user, but from a scene, so to see this requests, you should grep for RunScene .&lt;br /&gt;
&lt;br /&gt;
For a complete list of the log levels, see the [[Luup_Loglevels|Luup Log Levels]] page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
So, if you want to watch the router's logs and see what commands are being sent to the various devices, do this: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
Now from Vera's dashboard, send commands to the devices and you'll see them in the log. The | grep '^08' means to filter only lines that start with 08, meaning log level 08 (&amp;quot;Commands&amp;quot;). tail -f means &amp;quot;follow the log&amp;quot;. To stop the tail and get back to the console, if you used ssh to login, you just press Ctrl+C. Unfortunately, often times telnet doesn't forward Ctrl+C, so, when using telnet you need to press Ctrl+Z and then type this to kill the tail command: killall tail; fg &lt;br /&gt;
&lt;br /&gt;
To watch the traffic on the Z-Wave serial bus, type: &lt;br /&gt;
&lt;br /&gt;
'''cd /var/log/cmh&amp;lt;br&amp;gt; tail -f 9-ZWave.log | grep '^41\|^42'''' &lt;br /&gt;
&lt;br /&gt;
which means show log level 41 or 42. Normally Vera is polling all the nodes every few seconds, so the logs fill up quickly with Z-Wave traffic from the polling. If you want to turn off automatic polling temporarily for this session so the logs aren't cluttered with polling traffic, type: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 966 5 0'''&amp;lt;br&amp;gt;(assuming the Z-Wave device is #9, as default, add 225 1 to make the change permanent) &lt;br /&gt;
&lt;br /&gt;
To force a poll of device 13, type:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 966 2 13 5 UPDATE''' &lt;br /&gt;
&lt;br /&gt;
Next you can send &amp;quot;COMMAND: #191 - Send Code&amp;quot; to either a Z-Wave Node and the parameter 9 (Text) is a command, or send it to the Z-Wave device and it is a frame. The contents of text are a string of hex or decimal numbers separated with spaces, dashes or underscores, and hex values are preceded with 0x or x. So assuming a dimmable light is device 20 in node 15, either command below will dim it to 50%: &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;0 x13 15 0x3 0x26 0x1 50 4 1&amp;quot;''' #send data (func id x13) to node 15 command class 0x26 command 0x1 (set multi level) to 10% (size=3) with transmit options=4 and funcid=1 &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 20 1 191 9 &amp;quot;x26 x1 50&amp;quot;''' #send the message directly to device 20 (the node, not 9 the Z-Wave dongle), so the node id and 'send data' frame are assumed &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Node=7&amp;amp;amp;Data=x26-x1-20&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=0-x13-7-0x3-0x26-0x1-50-4-1&amp;quot; node 7 to 20% &lt;br /&gt;
&lt;br /&gt;
'''/usr/bin/MessageSend localhost 0 14 1 191 9 &amp;quot;x85 2 1&amp;quot;''' #Tell device 14 to report its association group 1 &lt;br /&gt;
&lt;br /&gt;
Ask node 4 (a thermostat) to report its temperature: &amp;quot;0 0x13 0x4 0x2 0x40 0x2 5 1&amp;quot; &lt;br /&gt;
&lt;br /&gt;
You can also put an R in front of the binary data, and include the full frame, and it simulates a received frame on the serial api, rather than sending a frame. So to simulate receiving a FUNC_ID_ZW_APPLICATION_UPDATE from node 1 run:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 191 9 &amp;quot;R0x1 0x9 0x0 0x49 0x84 0x1 0x3 0x2 0x2 0x1 0x38&amp;quot;'''&amp;lt;br&amp;gt; or an encrypted message from node 29 with FUNC_ID_APPLICATION_COMMAND_HANDLER, COMMAND_CLASS_SECURITY: '''&amp;quot;R0x01 0x1C 0x00 0x04 0x00 29 0x16 0x98 0x81 0xEC 0xE1 0x10 0x56 0xFC 0x13 0xDF 0x04 0x45 0x60 0x24 0xA8 0x43 0x89 0xE8 0x22 0x36 0x15 0xA9 0xB1 0x1C&amp;quot;''' &lt;br /&gt;
&lt;br /&gt;
--Luup update: wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Data=R0x1-0x16-0x0-0x4-0x0-0x4-0x10-0x8f-0x1-0x4-0x3-0x80-0x3-0x64-0x2-0x46-0x4-0x2-0x46-0x7-0x2-0x84-0x7-0x15&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Note that the logs will rotate regularly, meaning the DCERouter.log is archived as DCERouter.log.1.gz, and the old DCERouter.log.1.gz becomes DCERouter.log.2.gz. This is handled by the root cron process that runs /usr/bin/Rotate_Logs.sh. &lt;br /&gt;
&lt;br /&gt;
Every time you do something with Vera this results in a &amp;quot;job&amp;quot;. So let's assume you want to see what Vera is doing to configure a device. Type 'date' to see the date/time. Click the 'configure right now' button for the device. Type ''grep AddJob 9-ZWave.log'' to see all the log entries with 'AddJob' in them. Each one is given a number, and an abbreviated description. Say the first job after the 'date' is ''10 01/26/09 16:35:51.640 JobHandler::AddJob job#6&amp;amp;nbsp;:conf_jh#9 (0x00DD7390) P:40 S:0 &amp;amp;lt;00DD7390&amp;amp;gt; conf_jh#9 type ZWJob_ConfigureNode first 0'' This means it's job#6, the name 'conf_jh#9' means it's a configure job from the main job handler for node #9. You may see lots of other jobs right after #6 to do things like set the Version/Manufacturer, set Associations, etc., because the main configure job (#6) may spawn many other jobs. To see all the log entries for job #6, type ''grep &amp;quot;job#6&amp;quot; 9-ZWave.log''. Pay attention to the lines with m_eJobStatus which indicate the status, such as ''m_eJobStatus Job completed ok''. Let's say you want to see what data is being sent/received as part of job#6, you could do this: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log'' so you see all log entries for job #6, all incoming/outgoing data, plus critical errors (1) and warnings (5). Look for the line 'ready to run' in the logs, which will indicate where job #6 is starting. The logs are color coded, and the less that comes with busybox in Vera doesn't support the -R parameter to view the logs in color, which is much easier to read. So, you can set a root password if you haven't already (type ''passwd''), and then use scp to copy the log files from Vera to another Linux/Mac/Windows with cygwin pc, and then run: ''grep 'job#6\|^41\|^42\|^01\|^05' 9-ZWave.log | less -R'' to see just the filtered portion of the logs in color. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; You can also use MessageSend to send Vera's normal DCE commands directly to devices. The ID's are the same as LinuxMCE. You can also '''tail -f DCERouter.log | grep '^08'''' &lt;br /&gt;
&lt;br /&gt;
From the console, if you want to see if a device is configured, enable verbose logging: '''/usr/bin/VerboseLogging.sh enable''', restart the Z-Wave device: '''/usr/bin/MessageSend localhost 0 9 7 1''' then wait for it to finish checking all the devices and '''grep UpdateNode 9-ZWave.log'''. You'll see: '''ZWaveJobHandler::UpdateNodes node 13 PK_DeviceTemplate 37 type ZWaveNonDimmableLight PK_Device 19 cap 0xc9 sec 0xc res 0x0 bas 0x4 gen 0x10 spe 0x3 config 1 LS (on/off)-45W-IPCAM classes 25,27,2b,2c,72,73,77,82,85,86,91,ef,''' config 1 means the device is configured. To reconfigure a device from the command line, send it command 776. For this device it would be: '''/usr/bin/MessageSend localhost 0 19 1 776'''. &lt;br /&gt;
&lt;br /&gt;
Reset the Z-Wave network:&amp;lt;br&amp;gt;'''/usr/bin/MessageSend localhost 0 9 1 776 51 SIS''' &lt;br /&gt;
&lt;br /&gt;
Do a 'soft reset' that doesn't lose any devices, but resets the dongle:&amp;lt;br&amp;gt; '''/usr/bin/MessageSend localhost 0 9 1 776 51 SOFT'''&lt;br /&gt;
&lt;br /&gt;
== Z-Wave Log Messages  ==&lt;br /&gt;
&lt;br /&gt;
=== Z-Wave LastNote  ===&lt;br /&gt;
&lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Timed out waiting for the node to reply&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Node is not configured&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Unable to get any information on node&amp;quot;''' &lt;br /&gt;
* '''Status=&amp;quot;Aborted&amp;quot; LastNote=&amp;quot;Transmit failed with code: 1&amp;quot;''': ''Code 1'' means that Vera received no acknowledge from the device. This can happen either because the node is out of range, there are interferences or because of routing issues.&lt;br /&gt;
&lt;br /&gt;
== Remote Upgrade with preserve settings  ==&lt;br /&gt;
&lt;br /&gt;
curl -k -s -S --fail --retry 3 -o /tmp/firmware.img http://download.controlmyhouse.net/betafirmware/ftp/wl500gP-1.0.543.trx &lt;br /&gt;
&lt;br /&gt;
/usr/bin/cmh-upgrade.sh &lt;br /&gt;
&lt;br /&gt;
== Z-Wave routing matrix  ==&lt;br /&gt;
&lt;br /&gt;
See http://forum.micasaverde.com/index.php?topic=2099.msg8292#msg8292 and http://forum.micasaverde.com/index.php?topic=5130.0.&lt;br /&gt;
&lt;br /&gt;
== Z-Wave stress test  ==&lt;br /&gt;
&lt;br /&gt;
Start a stress test of the Z-Wave network with this command. Stop by doing a /usr/bin/Reload.sh &lt;br /&gt;
&lt;br /&gt;
wget &amp;quot;http://127.0.0.1:49451/data_request?id=lu_action&amp;amp;amp;DeviceNum=1&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&amp;amp;amp;action=SendData&amp;amp;amp;Stress=X&amp;quot; &lt;br /&gt;
&lt;br /&gt;
where X is: &lt;br /&gt;
&lt;br /&gt;
 #define STRESS_TEST_CONSTANT		1  // Constant BASIC_SET's&lt;br /&gt;
 #define STRESS_TEST_NEIGHBOR_UPDATE	2  // Constant Neighbor updates&lt;br /&gt;
 #define STRESS_TEST_WATCHDOG		3  // Constant Watchdog checks -- bugs in the Z-Wave serial API cause this to crash&lt;br /&gt;
 #define STRESS_TEST_SOFT_RESET		4  // Constant soft resets&lt;br /&gt;
&lt;br /&gt;
== Dead battery operated devices  ==&lt;br /&gt;
&lt;br /&gt;
Vera does not flag malfunctioning battery operated devices on the GUI.&lt;br /&gt;
&lt;br /&gt;
Use the following code to log all malfunctioning battery operated devices to a file:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5100.msg28346#msg28346&lt;br /&gt;
&lt;br /&gt;
Use the following code to get email notifications about malfunctioning battery operated devices:&lt;br /&gt;
&lt;br /&gt;
http://forum.micasaverde.com/index.php?topic=5130.0&lt;br /&gt;
&lt;br /&gt;
== Demo Mode ==&lt;br /&gt;
&lt;br /&gt;
Normally the state of a device changes after the Z-Wave command completes.  If, for demos, you want to be able to show the state change immediately, whether or not the job actually succeeds, open this URL:&lt;br /&gt;
&lt;br /&gt;
http://__ip_of_vera__:3480/data_request?id=lu_variableset&amp;amp;DeviceNum=1&amp;amp;serviceId=urn:micasaverde-com:serviceId:HaDevice1&amp;amp;Variable=SetState&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
It takes effect on the next reload.&lt;br /&gt;
&lt;br /&gt;
== Not getting status changes with door locks, or door locks out of sync  ==&lt;br /&gt;
&lt;br /&gt;
This is a commonly reported problem.  To debug this:&lt;br /&gt;
&lt;br /&gt;
(1) Turn on verbose logging: click Advanced from the tool box, logs tab.&lt;br /&gt;
&lt;br /&gt;
(2) Temporarily turn off polling so the logs don't have a bunch of background traffic: uncheck the poll nodes from the Z-Wave/options tab and click save.  You can turn polling back on when you're done&lt;br /&gt;
&lt;br /&gt;
(3) Wait a couple minutes after saving for Vera to settle down so the logs aren't going like crazy.  &lt;br /&gt;
&lt;br /&gt;
(4) Get Putty, a free Windows ssh client.  Just google for putty download.  You don't need to install it, just save it to your desktop.  Run it, put Vera's IP in the host name, leave SSH checked and click Open.  The user name is '''root''' and the password is on the bottom of Vera; it's the same as the wifi password or house id.  If you don't see the root password, see [[Getting the root password]].&lt;br /&gt;
&lt;br /&gt;
(5) Once you're logged in, type this command: &lt;br /&gt;
   &lt;br /&gt;
   tail -f /var/log/cmh/LuaUPnP.log | grep '^4\|^01\|HandlePoll\|^06'&lt;br /&gt;
&lt;br /&gt;
(6) You'll be following (tailing) Vera's logs.  grep is a filter to limit what you see to lines that start with 4 (which are the raw Z-Wave traffic--41 is traffic sent to Vera's Z-Wave chip, 42 is from the Z-Wave chip), lines that start with 01 are critical errors, lines that start with 06 are state changes, like lock/unlock, and lines containing the word HandlePoll indicate how Vera is handling any incoming data.  See [[Luup_Loglevels]]  If your tail command terminates, it means the logs rotated.  Hit the up arrow to bring the command up again, and enter to restart it.&lt;br /&gt;
&lt;br /&gt;
(7) Confirm that it's working by turning on and off a light from Vera's dashboard.  You should see some ZWave traffic (41 and 42 lines), and a status change (06 lines) for Target and Status.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(8) Now have someone go next to the lock.  Before they do anything hit enter a few times to add some blank space so you can clearly see if there's new log activity.  If there's no log activity at all, not even 41 and 42 lines, that means there's no Z-Wave traffic.  So the lock is not sending Vera any messages.  If you see traffic, you should also see a status change (06 line) to indicate the door is now locked or unlocked.  If you don't, copy what you see in putty by just highlighting it with the mouse.  Putty automatically copies anything you copy into the clipboard.  Paste it into an email you send to support.&lt;br /&gt;
&lt;br /&gt;
== Manual routing ==&lt;br /&gt;
&lt;br /&gt;
If you are using Z-Wave 3.20, you can go to the advanced settings for a device, add a variable with the service id: urn:micasaverde-com:serviceId:ZWaveDevice1 and the variable name: ManualRoute and the value is a dot separated list of Z-Wave node ID's, just like the AutoRoute variable.  The Auto route variable may be something like this: &amp;quot;2-20x,7-59x,2.7-78&amp;quot;.  This means there are 3 routes found.  #1 uses node 2 as an intermediary, and it has a 'score' of 20.  The score is a measure of latency and accuracy, the lower number is better.  The 'x' that follows means the last attempt to use it failed, so it won't be used anymore.  The next route uses node #7, it scored worse, and also failed.  The 3rd route uses node 2 &amp;amp; 7.  It had the worst score (78), but it's currently working (no x).&lt;br /&gt;
&lt;br /&gt;
== Very large Z-Wave networks ==&lt;br /&gt;
&lt;br /&gt;
As part of the Heal/Repair process, each Z-Wave node is asked to discover all its neighbors.  This is a standard Z-Wave function and is built into the Z-Wave module and is performed the same way on all Z-Wave controllers.  The problem is that the amount of time it takes the Z-Wave network to perform this function grows exponentially based on the number of Z-Wave nodes.  So in a really large Z-Wave network, with say 150 nodes, it can take more than 10 minutes per node to do the discovery, which means the heal process can take days.  And during the Z-Wave node discovery the entire Z-Wave network is unavailable.  We have a built-in watchdog, though, so that after 10 minutes it aborts the neighbor node discovery.  Therefore, for large networks, the heal process may not complete at all and Z-Wave's built-in routing may never work.  There is a solution which is to use MIOS routing instead.  To do this, you need to build a network with the newer Z-Wave standard, 3.20.  Go into Setup, Z-Wave Settings, Options.  If the Version is not already 3.20, then check the option: Use Z-Wave version 3.20 instead of 2.78, then click save, then wait 5 minutes for it to re-flash the built-in Z-Wave chip, then go back into Setup, Z-Wave Settings, Advanced, and choose Reset Z-Wave network.  After a minute, confirm the version is 3.20.  Now check the option under Options &amp;quot;Use MiOS routing instead of Z-Wave (requires 4.5)&amp;quot;, and uncheck &amp;quot;Limit neighbors to Z-Wave discovery (requries MiOS routing)&amp;quot;.  Then click Save.  Pair your Z-Wave devices as normal.  When you are all finished, do a repair network by choosing Z-Wave Settings, Repair, and click 'Go'.  The Repair may take longer, however once it completes, you should be able to get a larger Z-Wave network to operate than you otherwise would.&lt;br /&gt;
&lt;br /&gt;
== Association ==&lt;br /&gt;
&lt;br /&gt;
Z-Wave associations for a device are stored in the UPNP Variable service: urn:micasaverde-com:serviceId:ZWaveDevice1 variable: AssociationSet.  You can view this by clicking the settings for a device, going to the advanced tab, and finding the AssociationSet variable.  The associations are ; delimited, with the first digit being the group number followed by a comma separated list of nodes to be associated with that group.  Note these are Z-Wave node ID's, not device ID's (ie the 'altid' in the UI).  For multi-channel there is a . following the node id with the endpoint id.  Example: 1,3.4,7;2,5.1,8  meaning group #1, node #3 endpoint #4, node #7 is non-multi-channel, group #2 is associated with node #5 endpoint #1, and with node #8.&lt;br /&gt;
&lt;br /&gt;
== Node version ==&lt;br /&gt;
&lt;br /&gt;
The version info variable contains the version data reported by the node, like this: 3,2,78,3,62  Which is the library type, the zwave version &amp;amp; sub version, and the manufacturer version and sub version.  So this node is running Z-Wave 2.78, manufacturer version 3.62.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Remotec_IRBlaster</id>
		<title>Remotec IRBlaster</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Remotec_IRBlaster"/>
				<updated>2012-05-08T02:02:02Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Remotec IRBlasters are partially supported in firmware versions 1.5.346 and higher.&lt;br /&gt;
&lt;br /&gt;
1.  If you haven't already included them in your network, go to Device, Add Devices, Add Z-Wave devices, and include the Remotec like any other Z-Wave device.  The 'z-wave include' button is marked PROG on the side of the 6-port blaster, and it's the big black round button on the top of the single port blaster.  NOTE: The Remotec will not include or exclude unless it is set to 'channel 1'.  If you have problems, tap the Prog button and confirm the LED blinks one time.  If not, see the manual to put it to channel 1.&lt;br /&gt;
&lt;br /&gt;
2.  After it is included, go to Devices, Add Device, and choose Add IR Device.&lt;br /&gt;
&lt;br /&gt;
3.  Choose the IR Blaster from the 'use transmitter' pull-down.  If you have a 6-port blaster, you will see the blaster + 6 ports.  NOTE: In firmware 1.5.346 you should choose the blaster itself, not one of the 6 ports.&lt;br /&gt;
&lt;br /&gt;
4.  Choose 'Manual setup' because the Remotec blasters have their own codesets.&lt;br /&gt;
&lt;br /&gt;
5.  You will then need to enter the codeset number.  Do not enter the 0 in front of a codeset.  If the manual says 0251, use 251.  If you have multiple codesets, or are not sure which one is best, you can enter several codesets separated with a comma.  For example, if you have a Samsung TV, you'll see there are 6 possible codesets.  If you don't know which one to use, enter them all like this: 251,261,351,1191,1311,1911&lt;br /&gt;
&lt;br /&gt;
6.  After you click 'Create Device', your new device will appear on the Devices, A/V Gear. Choose the 'control' button to bring up the remote control to test your new device.&lt;br /&gt;
&lt;br /&gt;
7.  If you entered multiple codesets, and the remote isn't working, there's a button in the upper right corner of the remote to toggle through all the codesets.  It will say #1 at first, meaning, we'll be using the first codeset you entered.  Click it to try the second codeset, third, etc., until you've tried them all and it comes back to #1.  Try each one until you find the one that works best.  It will continue to use whatever is the last codeset you selected, so you only need to do this once.  If you only entered one codeset, this button will not be there.&lt;br /&gt;
&lt;br /&gt;
NOTE: Due to a bug in 1.5.346, it won't automatically program the remotec with the codeset you entered until you hit the button described in step 7.  So if you add a device with only 1 codeset it won't work.  A temporary workaround is that if you you must enter at least 2 codesets.  If the codeset is 251, then enter codesets 1,251 in step #5.  This way you can hit the #1 button in step 7 to cycle to the 2nd codeset, and it will program the Remotec to use codeset #251.  This bug only affects release 1.5.346.&lt;br /&gt;
&lt;br /&gt;
Note that once you have confirmed the device is working, you can include this A/V device in scenes.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/GE_Advanced_Remote_45601</id>
		<title>GE Advanced Remote 45601</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/GE_Advanced_Remote_45601"/>
				<updated>2012-04-25T20:02:37Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Place Vera in Add Device mode.  &lt;br /&gt;
&lt;br /&gt;
For the GE 45601: On the GE Remote, press and hold Setup until the display reads &amp;quot;Light Setup&amp;quot;.  Press the right arrow until it says &amp;quot;Transfer&amp;quot;.  Press OK.  Press the right arrow until it says &amp;quot;Receive&amp;quot;.  Press OK.&lt;br /&gt;
&lt;br /&gt;
For the GE 45600: On the GE remote, press and hold setup until both the red and green LED's blink twice.  Then press 9, 6, 7 on the numeric keypad.&lt;br /&gt;
&lt;br /&gt;
The GE Remote will appear on your dashboard as a device.  Click the setup icon (wrench) and on the scenes tab you can pick scenes to assign to the 9 scene buttons.  Create the scenes in Vera like normal.  Scenes can include adjusting thermostats, turning lights on or off, or anything else you can do in a scene.  To activate one of the scenes, press the 'Scene' button on the remote to ensure it's in Scene mode.  Then the 9 scene on buttons will trigger whatever scene you specified in the setup.  Note that the scene 'off' buttons won't do anything.  If you want to be able to turn lights off, you should create a scene with the lights to turn off.  To use the 9 off buttons you will need to program the scenes as described in the GE manual on the remote directly.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/GE_Advanced_Remote_45601</id>
		<title>GE Advanced Remote 45601</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/GE_Advanced_Remote_45601"/>
				<updated>2012-04-25T19:58:35Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Place Vera in Add Device mode.  On the GE Remote, press and hold Setup until the display reads &amp;quot;Light Setup&amp;quot;.  Press the right arrow until it says &amp;quot;Transfer&amp;quot;.  Press OK.  Press the right arrow until it says &amp;quot;Receive&amp;quot;.  Press OK.&lt;br /&gt;
&lt;br /&gt;
The GE Remote will appear on your dashboard as a device.  Click the setup icon (wrench) and on the scenes tab you can pick scenes to assign to the 9 scene buttons.  Create the scenes in Vera like normal.  Scenes can include adjusting thermostats, turning lights on or off, or anything else you can do in a scene.  To activate one of the scenes, press the 'Scene' button on the remote to ensure it's in Scene mode.  Then the 9 scene on buttons will trigger whatever scene you specified in the setup.  Note that the scene 'off' buttons won't do anything.  If you want to be able to turn lights off, you should create a scene with the lights to turn off.  To use the 9 off buttons you will need to program the scenes as described in the GE manual on the remote directly.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/GE_Advanced_Remote_45601</id>
		<title>GE Advanced Remote 45601</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/GE_Advanced_Remote_45601"/>
				<updated>2012-04-25T19:46:18Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;Place Vera in Add Device mode.  On the GE Remote, press and hold Setup until the display reads &amp;quot;Light Setup&amp;quot;.  Press the right arrow until it says &amp;quot;Transfer&amp;quot;.  Press OK.  Press t...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Place Vera in Add Device mode.  On the GE Remote, press and hold Setup until the display reads &amp;quot;Light Setup&amp;quot;.  Press the right arrow until it says &amp;quot;Transfer&amp;quot;.  Press OK.  Press the right arrow until it says &amp;quot;Receive&amp;quot;.  Press OK.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/GE_ZW5301_45631</id>
		<title>GE ZW5301 45631</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/GE_ZW5301_45631"/>
				<updated>2012-04-25T03:41:24Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The GE ZW5301 / 45631 is a wall-mountable Z-Wave scene controller.  Be sure to remove the tabs behind the battery.&lt;br /&gt;
&lt;br /&gt;
In Vera, go into 'add device' mode.  On the scene controller, hold the add and remove buttons until the orange led blinks twice, then immediately press the four 'scene off / down' buttons in order from top to bottom.  If the device doesn't add, try doing a factory reset on it by pressing and holding both the left side (OFF) of the #1 Group/Scene button (upper left) and the &amp;quot;Remove&amp;quot; button until the Green LED blinks twice (approx 3-6 seconds).&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/GE_ZW5301_45631</id>
		<title>GE ZW5301 45631</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/GE_ZW5301_45631"/>
				<updated>2012-04-25T03:37:57Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;The GE ZW5301 / 45631 is a wall-mountable Z-Wave scene controller.  Be sure to remove the tabs behind the battery.  In Vera, go into 'add device' mode.  On the scene controller, ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The GE ZW5301 / 45631 is a wall-mountable Z-Wave scene controller.  Be sure to remove the tabs behind the battery.&lt;br /&gt;
&lt;br /&gt;
In Vera, go into 'add device' mode.  On the scene controller, hold the add and remove buttons until the orange led blinks twice, then immediately press the four 'scene off / down' buttons in order from top to bottom.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Serial_Supported_Hardware</id>
		<title>Serial Supported Hardware</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Serial_Supported_Hardware"/>
				<updated>2012-04-04T15:53:54Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* USB Devices */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:User Instructions]]&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
This page is not yet complete...&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This is a page for Supported USB, or USB-Serial, interface devices.&lt;br /&gt;
&lt;br /&gt;
USB, and USB-Serial, devices need to be recognized by Vera's platform before they can be used to interface with the target device (through a Luup Module).  There are many USB-Serial devices out there, and not all will work out of the gate.&lt;br /&gt;
&lt;br /&gt;
This page is intended to capture the list of known USB Devices that have been ''tried'' with Vera, along with their current status, and any information required to get them working.&lt;br /&gt;
&lt;br /&gt;
This is a wiki, so feel free to add to the page. &lt;br /&gt;
&lt;br /&gt;
=Disclaimer=&lt;br /&gt;
'''IMPORTANT! The devices listed here have been added by installers, technicians and users like yourself. Results may vary upon installations. MiCasaVerde does not guarantee operation and compatibility with your installation. The listed devices were found to work with their specific installation. Mixing different series and brands of equipment is not guaranteed in any way to work with other series and brands. It is very likely that users have not fully tested all features of the devices, so it is possible that a device listed here as compatible, will not prove compatible with your hardware. If you are editing this wiki DO NOT REMOVE a listed working device if it hasn't worked for you. Seek help to get the device to work under your individual circumstance. If you are adding to this wiki, please provide links to data for the device and add any tips you feel may benefit someone wanting to implement the device into an installation.''' &lt;br /&gt;
&lt;br /&gt;
= USB Devices =&lt;br /&gt;
&lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;width: 1220px;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Manufacturer &lt;br /&gt;
! Model # &lt;br /&gt;
! Status &lt;br /&gt;
! Date Purchased &lt;br /&gt;
! Chipset &lt;br /&gt;
! Specs &lt;br /&gt;
! Purchased from &lt;br /&gt;
! Added by User &lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| USB-UIRT &lt;br /&gt;
| USB-UIRT &lt;br /&gt;
| Working (1.0.918) &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| http://www.usbuirt.com/ &lt;br /&gt;
| http://www.usbuirt.com/ &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=2 micasaverde] &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| APC &lt;br /&gt;
| Back-UPS ES 750 &lt;br /&gt;
| Not Working &lt;br /&gt;
| &lt;br /&gt;
| APC HID &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=2618 guessed] &lt;br /&gt;
| Doesn't work in Vera 1.0.900. Requires installation of Kernel/OpenWRT modules to support USB-HID Interface for UPS. This one is listed in guessed's posting [http://forum.micasaverde.com/index.php?topic=1471.msg5570#msg5570]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= USB-Serial Devices  =&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;1220&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Manufacturer &lt;br /&gt;
! Model # &lt;br /&gt;
! Status &lt;br /&gt;
! Date Purchased &lt;br /&gt;
! #RS-232 Ports &lt;br /&gt;
! Chipset &lt;br /&gt;
! Specs &lt;br /&gt;
! Purchased from &lt;br /&gt;
! Added by User &lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| Future Electronics &lt;br /&gt;
| UC232R-10 &lt;br /&gt;
| Working &lt;br /&gt;
| &lt;br /&gt;
| 1 &lt;br /&gt;
| FTDI &lt;br /&gt;
| [http://www.ftdichip.com/Documents/DataSheets/Modules/DS_UC232R.pdf Link] &lt;br /&gt;
| [http://www.futureelectronics.com/en/Technologies/Product.aspx?ProductID=UC232R10FUTURETECHNOLOGYDEVICES2297802 futureelectronics.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=2 micasaverde] &lt;br /&gt;
| This one is listed in MiCasaVerde's posting [http://forum.micasaverde.com/index.php?topic=1170.msg4500#msg4500]&lt;br /&gt;
|-&lt;br /&gt;
| SerialGear &lt;br /&gt;
| 8XDB9-USB &lt;br /&gt;
| Not working &lt;br /&gt;
| &lt;br /&gt;
| 8 &lt;br /&gt;
| FTDI - FT8U232AM &lt;br /&gt;
| [http://www.ftdichip.com/Documents/DataSheets/ft232r08.pdf Link] &lt;br /&gt;
| [http://www.usbgear.com/computer_cable_details.cfm?sku=8XDB9-USB&amp;amp;cats=199&amp;amp;catid=199%2C478%2C474 usbgear.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=525 nanckekr] &lt;br /&gt;
| This one is listed in nanckekr's posting [http://forum.micasaverde.com/index.php?topic=1170.msg4484#msg4484]  Uses some sort of &amp;quot;dual&amp;quot; FTDI Chipset that causes Vera to lockup.  The OS is correctly recognizing the Chip, and all 8x Serial ports, but Vera's &amp;quot;Serial Port Config&amp;quot; isn't working correctly against it as it's using a naming strategy that creates duplicate names.&lt;br /&gt;
|-&lt;br /&gt;
| Bytecc &lt;br /&gt;
| BT-DB925 &lt;br /&gt;
| Manual &lt;br /&gt;
| &lt;br /&gt;
| 1 &lt;br /&gt;
| Prolific - PL-2303 &lt;br /&gt;
| &lt;br /&gt;
| [http://www.monoprice.com/products/product.asp?c_id=103&amp;amp;cp_id=10311&amp;amp;cs_id=1031104&amp;amp;p_id=2067&amp;amp;seq=1&amp;amp;format=2 monoprice.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=2618 guessed] &lt;br /&gt;
| This one is listed in guessed's posting [http://forum.micasaverde.com/index.php?topic=1471.msg5512#msg5512]. It requires a series of manual configuration steps, and OS-Level access to Vera, to get it working.&lt;br /&gt;
|-&lt;br /&gt;
| BAFO &lt;br /&gt;
| DX SKU 5947 &lt;br /&gt;
| Manual &lt;br /&gt;
| &lt;br /&gt;
| 1 &lt;br /&gt;
| Prolific - PL-2303 &lt;br /&gt;
| N/A &lt;br /&gt;
| [http://www.dealextreme.com/details.dx/sku.5947 dealextreme.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=7 325xi] &lt;br /&gt;
| Well built, recognized by OpenWrt, Ubuntu, Windows, etc. On Vera it will require manual edits made through SSH. See details on nanckekr's post: [http://forum.micasaverde.com/index.php?topic=3025.msg12329#msg12329]&lt;br /&gt;
|-&lt;br /&gt;
| N/A &lt;br /&gt;
| DX SKU 22407 &lt;br /&gt;
| Not working &lt;br /&gt;
| &lt;br /&gt;
| 1 &lt;br /&gt;
| Prolific - PL-2303 &lt;br /&gt;
| N/A &lt;br /&gt;
| [http://www.dealextreme.com/details.dx/sku.22407 dealextreme.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=7 325xi] &lt;br /&gt;
| Intermittent USB recognition errors on Vera; but does work on Kamikaze&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
SYBA&lt;br /&gt;
&lt;br /&gt;
| N/A &lt;br /&gt;
| Not working &lt;br /&gt;
| &lt;br /&gt;
| 1 &lt;br /&gt;
| Prolific - PL-2303 &lt;br /&gt;
| N/A &lt;br /&gt;
| [http://www.monoprice.com/products/product.asp?c_id=103&amp;amp;cp_id=10311&amp;amp;cs_id=1031104&amp;amp;p_id=2276&amp;amp;seq=1&amp;amp;format=2 monoprice.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=7 325xi] &lt;br /&gt;
| USB recognition errors on Linux distros and OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp;SerialStuff*&lt;br /&gt;
| &amp;amp;nbsp;USBG-4FTDI*&lt;br /&gt;
| Working &lt;br /&gt;
| 11/2006 &lt;br /&gt;
| 4 &lt;br /&gt;
| FTDI FT232BL*&lt;br /&gt;
| &amp;amp;nbsp;? &lt;br /&gt;
| [http://www.mcmelectronics.com/product/83-10137 mcmelectronics.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=4678 michaelk] &lt;br /&gt;
| 4 serial ports. Just plugged it in and it worked. There's also a 2-port model from the same place- that MIGHT&amp;amp;nbsp;work also. I assume it's FTDI becasue vera names the ports &amp;quot;ftdi_sio&amp;quot;.&amp;amp;nbsp; Fires right up from vera1's u sb port- but in case power is an issue it has a 5v input on the back so you can make it self powered. It's pretty generic- no name- etc. but feels solid- metal case and never had a problem with it over the years on a pc.&amp;amp;nbsp;&amp;amp;nbsp; '''NOTE''':&amp;amp;nbsp; *=I&amp;amp;nbsp;think it's the same as this page [http://www.usbgear.com/USBG-4FTDI.html usbgear.com]&amp;amp;nbsp;where I found that info&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Ethernet-Serial Devices=&lt;br /&gt;
{| cellpadding=&amp;quot;2&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;width: 1220px;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Manufacturer &lt;br /&gt;
! Model # &lt;br /&gt;
! Status&lt;br /&gt;
! Date Purchased &lt;br /&gt;
! #RS-232 Ports &lt;br /&gt;
! Chipset&lt;br /&gt;
! Specs &lt;br /&gt;
! Purchased from &lt;br /&gt;
! Added by User &lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| WizNet&lt;br /&gt;
| WIZ110SR &lt;br /&gt;
| Working&lt;br /&gt;
| Jan 2010&lt;br /&gt;
| 1 &lt;br /&gt;
| WIZnet&lt;br /&gt;
| [http://wiznet.co.kr/en/pro02.php?&amp;amp;page=1&amp;amp;num=20 Link] &lt;br /&gt;
| [http://www.sparkfun.com/commerce/product_info.php?products_id=9476 sparkfun.com] &lt;br /&gt;
| [http://forum.micasaverde.com/index.php?action=profile;u=2618 guessed] &lt;br /&gt;
| This is a stripped down Ethernet-enabled Serial/RS-232 Port.  It's useful in situations where you might otherwise need a GC-100 to get &amp;quot;just a serial port&amp;quot; to connect to a TV, Amplifier etc.  Don't forget to get yourself a 5V Power supply to drive it, or alternatively use a USB-5V Power code (as I do).  Initial configuration of the device requires a Windows machine to run the configuration tool (DHCP, Baud Rate/Parity etc).  Note that getting this &amp;quot;connected&amp;quot; to Vera is a manual process at this time.  http://forum.micasaverde.com/index.php?topic=2989.0 .  I use [http://www.sparkfun.com/commerce/product_info.php?products_id=8639 USB-5v] to power mine from an existing USB Power source (a USB Port on my DirecTV unit).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Discussions=&lt;br /&gt;
*Forum Posting - [http://forum.micasaverde.com/index.php?topic=1471.0 How to make Vera recognize your USB-to-Serial Adapter]&lt;br /&gt;
*Forum Posting - [http://forum.micasaverde.com/index.php?topic=1170.0 Serial port:]&lt;br /&gt;
*Forum Posting - [http://forum.micasaverde.com/index.php?topic=1703.0 Attempts to get ser2net Proxy working on a remote router device]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Cooper_Aspire_Remote</id>
		<title>Cooper Aspire Remote</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Cooper_Aspire_Remote"/>
				<updated>2012-04-02T21:33:11Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: Created page with &amp;quot;These instructions are for the Cooper Aspire Handheld remote.  If you have previously been using the remote you should probably do a factory reset.  Press 'Menu', choose 'Setting...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These instructions are for the Cooper Aspire Handheld remote.&lt;br /&gt;
&lt;br /&gt;
If you have previously been using the remote you should probably do a factory reset.  Press 'Menu', choose 'Settings', choose 'Reset', and then press the Menu button again which is now marked 'Reset'.&lt;br /&gt;
&lt;br /&gt;
First put Vera into include mode, such as pressing the '+' button, or choose Devices, Add Devices, add Z-Wave devices, option 1.&lt;br /&gt;
&lt;br /&gt;
Next, to include the remote in Vera's network, press 'Menu', choose 'Settings', choose 'Replicate', choose 'Receive', choose 'From unknown controller'.  &lt;br /&gt;
&lt;br /&gt;
Note that it appears the Cooper remote uses it's own internal mechanism for creating scenes rather than the standard Z-Wave command classes, so you may not be able to create scenes within Vera which work on the Cooper remote.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Aeon_HomeEnergyMonitor</id>
		<title>Aeon HomeEnergyMonitor</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Aeon_HomeEnergyMonitor"/>
				<updated>2012-03-29T20:42:58Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you have version 3.58 or later of the HEM firmware (unrelated to Vera's firmware), it supports the ability to report in real-time whenever there is a change in the energy consumption.&amp;amp;nbsp; It generates a report for Vera whenever there is a change. &lt;br /&gt;
&lt;br /&gt;
For versions 3.57 and lower, the only way to get real time energy reporting was to have the HEM send Vera reports constantly, whether or not there was a change.&amp;amp;nbsp; This required powering the HEM with USB power.&amp;amp;nbsp; So we recommend using the USB port on the HEM to upgrade to firmware 3.58 or newer, as per the instructions on aeon-labs.com &lt;br /&gt;
&lt;br /&gt;
There have been reported issues with HEM firmware less than 3.61.  If you don't have 3.61, download this file (link to come)&lt;br /&gt;
&lt;br /&gt;
[[Category:User_Instructions]] [[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2012-03-27T04:29:37Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* function: sunset / sunrise */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP addess and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. &amp;quot;v2&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, &amp;lt;tt&amp;gt;is_ready&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;tt&amp;gt;&amp;lt;incoming&amp;gt; block&amp;lt;/tt&amp;gt; that only processes data if &amp;lt;tt&amp;gt;is_ready(lul_device)&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; parameter, if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device, which, if it's a string, is interpreted as a udn, and if it's a number, is the device number. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), device (string or number), [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP service+variable will be set to value for device, which if it's a string, is interpreted as a udn, and if it's a number, as a device id. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: value (string), time (number) &lt;br /&gt;
&lt;br /&gt;
If the service+variable or device does not exist, it returns nothing. Otherwise it returns the value of the UPnP service+variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). You can assign just the value to a variable, as follows:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc. &lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the WAP mobile phone plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    return lul_html&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns:&lt;br /&gt;
&lt;br /&gt;
'''Warning:''' luup.device_supports_service doesn't work reliably: http://forum.micasaverde.com/index.php?topic=5600.0&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (boolean), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to true if the device is failing. If device is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: boolean &lt;br /&gt;
&lt;br /&gt;
Returns true if it's past sunset and before sunrise. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
'''Warning:''' luup.sleep doesn't work reliably: http://bugs.micasaverde.com/view.php?id=1480&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a unix timestamp (ie the seconds since 1/1/1970 in UTC time).  You can do a diff with os.time to see how long it will be for the next event.  luup.sunset-os.time is the number of seconds before the next sunset.  Be sure the location and timezone are properly set or the sunset/sunrise will be wrong.&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), id (string), description (string), device_type (string), device_filename (string), implementation_filename (string), parameters (string), embedded (boolean) [, invisible (boolean)]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt;. If &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
Pass in the &amp;lt;tt&amp;gt;ptr&amp;lt;/tt&amp;gt; which you received from the &amp;lt;tt&amp;gt;luup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt; which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as &amp;lt;tt&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the&amp;amp;nbsp;XML file with the UPnP device specification. The deviceType from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually. If the device_file contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the 'embedded' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; to separate service, variable and value, like this: &amp;lt;tt&amp;gt;service,variable=value\nservice&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If device is a string it is interpreted as a udn, if it's a number, as a device id. Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ip (string) port (number), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port. &lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean) &lt;br /&gt;
&lt;br /&gt;
In Lua a string can contain binary data, so data may be a binary block. If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nill if an error occurred. &lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Lua_extensions</id>
		<title>Luup Lua extensions</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Lua_extensions"/>
				<updated>2012-03-27T04:03:12Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* function: sleep */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to the [[http://lua.org Lua]] commands described in the [[http://www.lua.org/manual/5.1/ Lua reference manual]], you can also reference in your Lua code variables and functions from modules which the Luup engine provides as follows: &lt;br /&gt;
&lt;br /&gt;
== Module: luup  ==&lt;br /&gt;
&lt;br /&gt;
These are general purpose functions and variables. Call them by using the luup. module, such as:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Now running version: ' .. luup.version)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: device  ===&lt;br /&gt;
&lt;br /&gt;
The ID of this device instance, if it's running as part of a device &lt;br /&gt;
&lt;br /&gt;
=== variable: version, version_branch, version_major, version_minor  ===&lt;br /&gt;
&lt;br /&gt;
''version'' contains the version of the luup engine, such as &amp;quot;1.0.843&amp;quot;, as a string. The version consists of 3 numbers separated by a period: the branch, the major version, and the minor version. To make it easier to compare against a minimum acceptable version, ''version_branch, version_major and version_minor'' return each component as a number. You can put a comparison in the startup function in your Luup plugin and return false if the minimum version isn't met. The user will then see that the Luup device's startup check failed:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;if( version_branch ~= 1 or version_major ~= 0 or version_minor &amp;lt; 843 ) then&lt;br /&gt;
    luup.log(&amp;quot;I need version 1.0.843 minimum to run&amp;quot;)&lt;br /&gt;
    return false&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: longitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the longitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: latitude  ===&lt;br /&gt;
&lt;br /&gt;
Contains the latitude as a number, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: timezone  ===&lt;br /&gt;
&lt;br /&gt;
Contains the timezone as a number of hours offset from UTC, as found on the location tab in the setup UI.  It accounts for DST, so, for example, Pacific Standard time will be -8 or -9 depending on DST.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Contains 0 for MiOS &amp;lt; 1.5.250 (Vera V2) / &amp;lt; 1.5.249 (Vera V3).&lt;br /&gt;
&lt;br /&gt;
=== variable: city  ===&lt;br /&gt;
&lt;br /&gt;
Contains the city as a string, as found on the location tab in the setup UI. &lt;br /&gt;
&lt;br /&gt;
=== variable: devices  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the devices in the system as a table indexed by the device number.&lt;br /&gt;
&lt;br /&gt;
The members are:&lt;br /&gt;
* '''room_num''': (number) This is the number of the room the device is in. &lt;br /&gt;
* '''device_type''': (string) This is a string representing the type of the device.&lt;br /&gt;
* '''category_num''': (number) This is a category for the device.  See: [[Luup_Device_Categories]] for a list. &lt;br /&gt;
* '''device_num_parent''': (number) This is the number of the parent device. See: [[Lua Device Structure]] for details. &lt;br /&gt;
* '''ip''': (string) If this device is IP based, this is the IP address. &lt;br /&gt;
* '''mac''': (string) If this device is IP based, this is the MAC address. &lt;br /&gt;
* '''user''': (string) If this device is IP based and requires http authentication, this is the username&lt;br /&gt;
* '''pass''': (string) If this device is IP based and requires http authentication, this is the password&lt;br /&gt;
* '''id''': (string) If this device has an internal ID that is specific to the device, it is contained here. For example, for Z-Wave devices this is the Node ID, and for Insteon device it is the Insteon ID. &lt;br /&gt;
* '''embedded''': (boolean) If this device is embedded, it means that it doesn't have its own room or exist as a separate device. It should be considered part of its parent. Like a 3-in-1 sensor is a device with 3 embedded child devices. &lt;br /&gt;
* '''hidden''': (boolean) If true the user checked the 'hidden' box and doesn't want to see the device on the dashboard. &lt;br /&gt;
* '''invisible''': (boolean) If true the device is 'for internal use only' and shouldn't be presented to the user. &lt;br /&gt;
* '''description''': (string) This is the text description for the device as supplied by the user in the web UI. &lt;br /&gt;
* '''udn''': (string) This is the UDN for the UPnP device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example to log device #5's IP addess and its internal ID:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Device #5 ip: ' .. luup.devices[5].ip .. ' id: ' .. luup.devices[5].id)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This code will log all the attributes from all the devices:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;for k, v in pairs(luup.devices) do&lt;br /&gt;
    for k2, v2 in pairs(v) do&lt;br /&gt;
        luup.log(&amp;quot;Device #&amp;quot; .. k .. &amp;quot;:&amp;quot; .. k2 .. &amp;quot;=&amp;quot; .. &amp;quot;v2&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== variable: rooms  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the rooms as a table of strings indexed by the room number. Example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.log('Room #1 is called: ' .. luup.rooms[1])&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== variable: scenes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the scenes in the system as a table indexed by the scene number. The members are: room_num (number), description(string), hidden(boolean)&lt;br /&gt;
&lt;br /&gt;
=== variable: remotes  ===&lt;br /&gt;
&lt;br /&gt;
Contains all the remotes in the system as a table indexed by the remote id. The members are: remote_file (string), room_num (number), description(string) &lt;br /&gt;
&lt;br /&gt;
=== function: log  ===&lt;br /&gt;
&lt;br /&gt;
parameters: what_to_log (string), log_level (optional, number) &lt;br /&gt;
&lt;br /&gt;
return: nothing &lt;br /&gt;
&lt;br /&gt;
Writes what_to_log to the log, /var/log/cmh/LuaUPnP.log, with the given log_level, which is 50 by default. See: [[Luup Loglevels]] &lt;br /&gt;
&lt;br /&gt;
=== function: task  ===&lt;br /&gt;
&lt;br /&gt;
parameters: message (string), status (number), description (string), handle (number) &lt;br /&gt;
&lt;br /&gt;
return: handle (number) &lt;br /&gt;
&lt;br /&gt;
When the Luup engine is starting status messages are displayed for the various modules as they're initialized. Normally each device, including Luup devices, automatically log their status and the user is shown an error if the device doesn't start, such as if the 'startup' function returns an error. &lt;br /&gt;
&lt;br /&gt;
If you have other startup sequences which you want the user to see to know that startup hasn't finished yet, call this function passing in a handle of -1 for the first call. The status should be: 1=Busy, 2=Error, 4=Successful. Message is the current state, such as 'downloading', and description describes the module, like 'Smartphone UI'. After the first call, store the handle and pass it on future calls to update the status rather than add a new one. &lt;br /&gt;
&lt;br /&gt;
=== function: call_delay  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), seconds (number), data (string), thread (bool) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function ''function_name'' (the first parameter), which must be passed as a string, will be called in ''seconds'' seconds (the second parameter), and will be passed the string ''data''. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. function_name will only be called once and you must call call_delay again if you want it called again, or use call_timer instead. &lt;br /&gt;
&lt;br /&gt;
If thread is specified and is true or 1, the call back will be made in it's own thread and can block if needed. Normally it is called by a worker thread and is expected to return immediately.&lt;br /&gt;
&lt;br /&gt;
As of December 19, 2011, for all builds after 1.5.237, the 'thread' will be ignored.  Each Lua state has its own worker thread now, so all calls to call_delay and call_timer will occur in a separate thread.&lt;br /&gt;
&lt;br /&gt;
=== function: call_timer  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), type (number), time (string), days (string), data (string) &lt;br /&gt;
&lt;br /&gt;
returns: result (number) &lt;br /&gt;
&lt;br /&gt;
The function 'function_name', which must be passed as a string, will be called when the timer is triggered, and will be passed the string 'data'. The function returns 0 if successful. See: [[Luup Declarations#timed_function_callback]] for the names and syntax of the parameters that will be passed to function_name. &lt;br /&gt;
&lt;br /&gt;
Type is 1=Interval timer, 2=Day of week timer, 3=Day of month timer, 4=Absolute timer. For an interval timer, days is not used, and Time should be a number of seconds, minutes, or hours using an optional 'h' or 'm' suffix. Example: 30=call in 30 seconds, 5m=call in 5 minutes, 2h=call in 2 hours. For a day of week timer, Days is a comma separated list with the days of the week where 1=Monday and 7=Sunday. Time is the time of day in hh:mm:ss format. Time can also include an 'r' at the end for Sunrise or a 't' for Sunset and the time is relative to sunrise/sunset. For example: Days=&amp;quot;3,5&amp;quot; Time=&amp;quot;20:30:00&amp;quot; means your function will be called on the next Wed or Fri at 8:30pm. Days=&amp;quot;1,7&amp;quot; Time=&amp;quot;-3:00:00r&amp;quot; means your function will be called on the next Monday or Sunday 3 hours before sunrise. Day of month works the same way except Days is a comma separated list of days of the month, such as &amp;quot;15,20,30&amp;quot;. For an absolute timer, Days is not used, and Time should be in the format: &amp;quot;yyyy-mm-dd hh:mm:ss&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Data can be a string passed back to the function. The function should be declared so it takes a single argument, which is this data.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;function refreshCache(stuff)&lt;br /&gt;
    ....&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function startup()&lt;br /&gt;
    --&lt;br /&gt;
    -- Setup an interval-based timer to call refreshCache after 30 minutes.&lt;br /&gt;
    -- Note that if you want it to &amp;quot;recur&amp;quot; then you need to call this function again&lt;br /&gt;
    -- at the end of the refreshCache() implementation.&lt;br /&gt;
    --&lt;br /&gt;
    luup.call_timer(&amp;quot;refreshCache&amp;quot;, 1, &amp;quot;30m&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;SomeStuff&amp;quot;)&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: is_ready  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ready (boolean) &lt;br /&gt;
&lt;br /&gt;
version: UI5 and above&lt;br /&gt;
&lt;br /&gt;
Checks whether a device has successfully completed it's startup sequence. If so, &amp;lt;tt&amp;gt;is_ready&amp;lt;/tt&amp;gt; returns &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;. If your device shouldn't process incoming data until the startup sequence is finished, you may want to add a condition to the &amp;lt;tt&amp;gt;&amp;lt;incoming&amp;gt; block&amp;lt;/tt&amp;gt; that only processes data if &amp;lt;tt&amp;gt;is_ready(lul_device)&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; parameter, if it's a string, is interpreted as a udn.  If it's a number, it's interpreted as a device number.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;incoming&amp;gt;&lt;br /&gt;
    if (luup.is_ready(lul_device) == false) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    doSomething(lul_device)&lt;br /&gt;
&amp;lt;/incoming&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: call_action  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), action (string), arguments (table), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: error (number), error_msg (string), job (number), arguments (table) &lt;br /&gt;
&lt;br /&gt;
Invokes the UPnP service + action, passing in the arguments (table of string-&amp;amp;gt;string pairs) to the device, which, if it's a string, is interpreted as a udn, and if it's a number, is the device number. If the invocation could not be made, only error will be returned with a value of -1. Otherwise, all 4 values are returned. error is 0 if the UPnP device reported the action was successful. arguments is a table of string-&amp;amp;gt;string pairs with the return arguments from the action. If the action is handled asynchronously by a Luup job, then the job number will be returned as a positive integer. &lt;br /&gt;
&lt;br /&gt;
Example to dim device #5 to 50%:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local lul_arguments = {}&lt;br /&gt;
lul_arguments[&amp;quot;newLoadlevelTarget&amp;quot;] = 50&lt;br /&gt;
lul_resultcode, lul_resultstring, lul_job, lul_returnarguments = luup.call_action(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
                                                                                  &amp;quot;SetLoadLevelTarget&amp;quot;, lul_arguments,&lt;br /&gt;
                                                                                  5)&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: variable_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), value (string), device (string or number), [startup (bool)] &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
The UPnP service+variable will be set to value for device, which if it's a string, is interpreted as a udn, and if it's a number, as a device id. If there are events or notifications tied to the variable they will be fired. &lt;br /&gt;
&lt;br /&gt;
Optionally, you can add an argument 'startup'. If startup is true, this change will be considered a startup value, and if the variable is set to it's existing value, events and notifications will ''not'' be fired. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_get  ===&lt;br /&gt;
&lt;br /&gt;
parameters: service (string), variable (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: value (string), time (number) &lt;br /&gt;
&lt;br /&gt;
If the service+variable or device does not exist, it returns nothing. Otherwise it returns the value of the UPnP service+variable and the time when the variable was last modified, as a unix time stamp (number of seconds since 1/1/1970). You can assign just the value to a variable, as follows:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;local value = luup.variable_get(&amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;, &amp;quot;LoadLevelTarget&amp;quot;, 5)&lt;br /&gt;
luup.log(&amp;quot;Dim level for device #5 is: &amp;quot; .. value)&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: attr_set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: attribute (string), value(string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sets the top level attribute for the device to value. Examples of attributes are 'mac', 'name', 'id', etc. &lt;br /&gt;
&lt;br /&gt;
=== function: register_handler  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), request_name (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
When a certain URL is requested from a web browser or other HTTP get, function_name will be called and whatever string it returns will be returned. &lt;br /&gt;
&lt;br /&gt;
See the WAP mobile phone plugin as an example:&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;luup.register_handler(&amp;quot;lug_WapRequest&amp;quot;,&amp;quot;wap&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
function lug_WapRequest (lul_request, lul_parameters, lul_outputformat)&lt;br /&gt;
    local lul_html = &amp;quot;&amp;lt;head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;title&amp;gt;Main&amp;lt;/title&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;/head&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;&amp;lt;body&amp;gt;\n&amp;quot; ..&lt;br /&gt;
                     &amp;quot;Choose a room:&amp;lt;br/&amp;gt;\n&amp;quot;&lt;br /&gt;
    return lul_html&lt;br /&gt;
end&amp;lt;/source&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The request is made with the URL: data_request?id=lr_[the registered name] on port 49451. So: http://192.168.1.1:49451/data_request?id=lr_wap will return the web page defined in the function lug_WapRequest in the example above. &lt;br /&gt;
&lt;br /&gt;
=== function: variable_watch  ===&lt;br /&gt;
&lt;br /&gt;
parameters: function_name (string), service (string), variable (string or nil), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Whenever the UPnP variable is changed for the specified device, which if a string is interpreted as a UDN and if a number as a device ID, ''function_name'' will be called. See [[Luup Declarations#watch_callback]] for the values that will be passed to ''function_name''. If variable is nil, ''function_name'' will be called whenever any variable in the service is changed. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: devices_by_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
=== function: device_supports_service  ===&lt;br /&gt;
&lt;br /&gt;
parameters: &lt;br /&gt;
&lt;br /&gt;
returns:&lt;br /&gt;
&lt;br /&gt;
'''Warning:''' luup.device_supports_service doesn't work reliably: http://forum.micasaverde.com/index.php?topic=5600.0&lt;br /&gt;
&lt;br /&gt;
=== function: set_failure  ===&lt;br /&gt;
&lt;br /&gt;
parameters: value (boolean), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: &lt;br /&gt;
&lt;br /&gt;
Luup maintains a 'failure' flag for every device to indicate if it is not functioning. You can set the flag to true if the device is failing. If device is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
=== function: is_night  ===&lt;br /&gt;
&lt;br /&gt;
parameters: none &lt;br /&gt;
&lt;br /&gt;
returns: boolean &lt;br /&gt;
&lt;br /&gt;
Returns true if it's past sunset and before sunrise. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
=== function: sleep  ===&lt;br /&gt;
&lt;br /&gt;
parameters: number of milliseconds &lt;br /&gt;
&lt;br /&gt;
returns: none &lt;br /&gt;
&lt;br /&gt;
Sleeps a certain number of milliseconds&lt;br /&gt;
&lt;br /&gt;
'''Warning:''' luup.sleep doesn't work reliably: http://bugs.micasaverde.com/view.php?id=1480&lt;br /&gt;
&lt;br /&gt;
=== function: sunset / sunrise ===&lt;br /&gt;
&lt;br /&gt;
parameters: none&lt;br /&gt;
&lt;br /&gt;
returns: The next sunset / sunrise in a unix timestamp (ie the seconds since 1/1/1970 in UTC time).  You can do a diff with os.time to see how long it will be for the next event.&lt;br /&gt;
&lt;br /&gt;
== Module: luup.inet  ==&lt;br /&gt;
&lt;br /&gt;
=== function: wget  ===&lt;br /&gt;
&lt;br /&gt;
parameters: URL (String), Timeout (Number), Username (String), Password (String) &lt;br /&gt;
&lt;br /&gt;
returns httpStatusCode (Number), content (String) &lt;br /&gt;
&lt;br /&gt;
This reads the URL and returns 2 variables: the first is a numeric error code which is 0 if successful, and the second is a string containing the contents of the page. If '''Timeout''' is specified, the function will timeout after that many seconds. The default value for '''Timeout''' is 5 seconds. If '''Username''' and '''Password''' are specified, they will be used for HTTP Basic Authentication. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module: luup.chdev  ==&lt;br /&gt;
&lt;br /&gt;
Contains functions for a parent to synchronize its child devices. Whenever a device has multiple end-points, the devices are represented in a parent/child fashion where the parent device is responsible for reporting what child devices it has and giving each one a unique id. For example in the sample [[Luup Somfy Walkthrough]] there is a parent device, which is the interface module that controls up to 16 blinds, and up to 16 child devices, one for each blind. As shown in that sample, the parent calls start, then enumerates each child device with append, and finally calls sync. You will need to pass the same value for device to append and sync that you passed to start. &lt;br /&gt;
&lt;br /&gt;
=== function: start  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: ptr (binary object) &lt;br /&gt;
&lt;br /&gt;
Tells Luup you will start enumerating the children of device. If device is a string it is interpreted as a udn, if it's a number, as a device id. The return value is a binary object which you cannot do anything with in Lua, but you do pass it to the append and sync functions. &lt;br /&gt;
&lt;br /&gt;
=== function: append  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), id (string), description (string), device_type (string), device_filename (string), implementation_filename (string), parameters (string), embedded (boolean) [, invisible (boolean)]&lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Adds one child to &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt;. If &amp;lt;tt&amp;gt;device&amp;lt;/tt&amp;gt; is a string it is interpreted as a udn, if it's a number, as a device id. &lt;br /&gt;
&lt;br /&gt;
Pass in the &amp;lt;tt&amp;gt;ptr&amp;lt;/tt&amp;gt; which you received from the &amp;lt;tt&amp;gt;luup.chdev.start&amp;lt;/tt&amp;gt; call. Give each child a unique id so you can keep track of which is which. You can optionally provide a &amp;lt;tt&amp;gt;description&amp;lt;/tt&amp;gt; which the user sees in the user interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; is the UPnP device type, such as &amp;lt;tt&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;device_filename&amp;lt;/tt&amp;gt; is specified, that is the name of the&amp;amp;nbsp;XML file with the UPnP device specification. The deviceType from the filename will override any &amp;lt;tt&amp;gt;device_type&amp;lt;/tt&amp;gt; you set manually. If the device_file contains the implementation file for this child device you do not need to specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;. Otherwise, if there is a Luup implementation for this child device and it's not being handled by the parent device, you can specify it in &amp;lt;tt&amp;gt;implementation_filename&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;tt&amp;gt;embedded&amp;lt;/tt&amp;gt; is true, the 'embedded' flag is set for the device which generally means that the parent and all the children will be displayed as one compound device, or group, rather than as separate devices which you can put in their own rooms. &lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;parameters&amp;lt;/tt&amp;gt; are UPnP service,variables you want set when the device is created. You can specify multiple variables by separating them with a line feed (\n) and use a &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; to separate service, variable and value, like this: &amp;lt;tt&amp;gt;service,variable=value\nservice&amp;lt;/tt&amp;gt;...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
luup.chdev.append(device, children,&lt;br /&gt;
    string.format(&amp;quot;Input-%d&amp;quot;, i), string.format(&amp;quot;Input %d&amp;quot;, i),&lt;br /&gt;
    &amp;quot;urn:schemas-micasaverde-com:device:TemperatureSensor:1&amp;quot;, &amp;quot;D_TemperatureSensor1.xml&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;, &amp;quot;urn:upnp-org:serviceId:TemperatureSensor1,CurrentTemperature=50&amp;quot;, true)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: sync  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ptr (binary object), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If device is a string it is interpreted as a udn, if it's a number, as a device id. Pass in the ptr which you received from the start function. Tells the Luup engine you have finished enumerating the child devices. If the child devices have changed in any way, the new device tree will be written to the configuration file and the Luup engine is reset. &lt;br /&gt;
&lt;br /&gt;
== Module: io  ==&lt;br /&gt;
&lt;br /&gt;
=== function: open  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number), ip (string) port (number), &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This opens a socket on 'port' to 'ip' and stores the handle to the socket in 'device'. The opening of a socket can take time depending on the network, and a Luup function should return quickly whenever possible because each top-level device's Lua implementation runs in a single thread. So the actual opening of the socket occurs asynchronously and this function returns nothing. You will know that the socket opening failed if your subsequent call to write fails. &lt;br /&gt;
&lt;br /&gt;
Generally you do not need to call the open function because the socket is usually started automatically when the Luup engine starts. This is because the user typically either (a) associates a device with the destination io device, such as selecting an RS232 port for an alarm panel, where the RS232 is proxied by a socket, or (b) because the configuration settings for the device already include an IP address and port. &lt;br /&gt;
&lt;br /&gt;
=== function: write  ===&lt;br /&gt;
&lt;br /&gt;
parameters: data (string), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: result (boolean) &lt;br /&gt;
&lt;br /&gt;
In Lua a string can contain binary data, so data may be a binary block. If 'device' is a string it is interpreted as a UDN; if it's a number, as a device ID. This sends data on the socket that was opened automatically or with the open function above, and associated to 'device'. If the socket is not already open, write will wait up to 5 seconds for the socket before it returns an error. Result is 'true' if the data was sent successfully, and is 'false' or nill if an error occurred. &lt;br /&gt;
&lt;br /&gt;
=== function: intercept  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
Normally when data comes in on a socket (I/O Port), the block of data is first passed to any pending jobs that are running for the device and are marked as 'waiting for data'. If there are none, or if none of the jobs' incoming data handlers report that they consumed (i.e. processed) the data, then the block of data is passed to the general 'incoming' function handler for the device. If you want to bypass this normal mechanism and read data directly from the socket, call intercept first to tell Luup you want to read incoming data with the read function. This is generally used during the initialization or startup sequences for devices. For example, you may need to send some data (a), receive some response (b), send some more data (c), receive another response (d), etc. In this case you would call 'intercept' first, then send a, then call read and confirm you got b, then call intercept again, then send c, then read d, and so on. &lt;br /&gt;
&lt;br /&gt;
You can call the read function without calling intercept and any incoming data will be returned by that function after it's called. The reason why you generally must call intercept is because normally you want to send some data and get a response. If you write the code like this ''send(data) data=read()'' then it's possible the response will arrive in the brief moment between the execution of send() and read(), and therefore get sent to the incoming data handler for the device. Intercept tells Luup to buffer any incoming data until the next read, bypassing the normal incoming data handler. So ''intercept() send(data) data=read()'' ensures that read will always get the response. If the device you're communicating with sends unsolicited data then there's the risk that the data you read is not the response you're looking for. If so, you can manually pass the response packet to the incoming data handler. &lt;br /&gt;
&lt;br /&gt;
**TBD: Add a function to do this**&lt;br /&gt;
&lt;br /&gt;
=== function: read  ===&lt;br /&gt;
&lt;br /&gt;
parameters: timeout (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: data (string) &lt;br /&gt;
&lt;br /&gt;
This reads a block of data from the socket. You must have called ''intercept'' previously so the data is passed. The time unit for ''timeout'' is seconds.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: is_connected  ===&lt;br /&gt;
&lt;br /&gt;
parameters: device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: connected (boolean) &lt;br /&gt;
&lt;br /&gt;
This function returns true if there is a valid IO port connected, otherwise returns false&lt;br /&gt;
&lt;br /&gt;
== Module: luup.job  ==&lt;br /&gt;
&lt;br /&gt;
=== function: status  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job_number (number), device (string or number) &lt;br /&gt;
&lt;br /&gt;
returns: job_status (number), notes (string) &lt;br /&gt;
&lt;br /&gt;
If '''job_number''' is invalid the function returns ''-1''. If '''device''' is a string it is interpreted as an UDN, if it's a number, as a device ID.&lt;br /&gt;
&lt;br /&gt;
This is the list with all job statuses and their meaning:&lt;br /&gt;
* '''-1''': No job, i.e. job doesn't exist.&lt;br /&gt;
*  '''0''': Job waiting to start.&lt;br /&gt;
*  '''1''': Job in progress.&lt;br /&gt;
*  '''2''': Job error.&lt;br /&gt;
*  '''3''': Job aborted.&lt;br /&gt;
*  '''4''': Job done.&lt;br /&gt;
*  '''5''': Job waiting for callback. Used in special cases.&lt;br /&gt;
*  '''6''': Job requeue. If the job was aborted and needs to be started, use this special value.&lt;br /&gt;
*  '''7''': Job in progress with pending data. This means the job is waiting for data, but can't take it now.&lt;br /&gt;
&lt;br /&gt;
=== function: set  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string), value (string) &lt;br /&gt;
&lt;br /&gt;
returns: nothing &lt;br /&gt;
&lt;br /&gt;
This stores a setting for a job. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&amp;lt;job&amp;gt;&lt;br /&gt;
    luup.job.set(lul_job, &amp;quot;comments&amp;quot;, &amp;quot;In progress...&amp;quot;)&lt;br /&gt;
    local comments = luup.job.setting(lul_job, &amp;quot;comments&amp;quot;)&lt;br /&gt;
    luup.log(&amp;quot;job comments = &amp;quot; .. comments)&lt;br /&gt;
&amp;lt;/job&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== function: setting  ===&lt;br /&gt;
&lt;br /&gt;
parameters: job (userdata), setting (string) &lt;br /&gt;
&lt;br /&gt;
returns: value (string) &lt;br /&gt;
&lt;br /&gt;
This returns a setting for a job. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Requests</id>
		<title>Luup Requests</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Requests"/>
				<updated>2012-03-21T22:41:24Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
In addition to sending requests using standard UPnP, you can also do most things using a simple HTTP requests.  Use the built-in URL &amp;lt;tt&amp;gt;data_request&amp;lt;/tt&amp;gt;, and pass the following on the URL:&lt;br /&gt;
*&amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; the id of the request (prior to 15 Oct 2010 all requests had an lu_ in front, which is now optional), &lt;br /&gt;
*&amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; the format in which you want a response as &amp;lt;tt&amp;gt;json&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;xml&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;text&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Not all requests support all &amp;lt;tt&amp;gt;output_format&amp;lt;/tt&amp;gt; options.  Here is a list of requests:&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=user_data&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
This returns the configuration data for Vera, which is a list of all devices and the UPnP variables which are persisted between resets as well as rooms, names, and other data the user sets as part of the configuration.&lt;br /&gt;
&lt;br /&gt;
==status==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
Or for a specific device: http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;UDN=uuid:4d494342-5342-5645-0002-000000000002 or http://ipaddress:3480/data_request?id=status&amp;amp;output_format=xml&amp;amp;DeviceNum=6&lt;br /&gt;
&lt;br /&gt;
This returns the current status for all devices including all the current upnp variables and the status of any active jobs.&lt;br /&gt;
&lt;br /&gt;
==sdata==&lt;br /&gt;
&lt;br /&gt;
This is an abbreviated form of user_data and status (sdata=summary data).  It allows a user interface that is only worried about control, and not detailed configuration, to get a summary of the data that would normally be presented to the user and to monitor the changes.  See [[UI_Simple]] for a walkthrough.&lt;br /&gt;
&lt;br /&gt;
==actions==&lt;br /&gt;
&lt;br /&gt;
==device==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=3&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=rename&amp;amp;device=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=device&amp;amp;action=delete&amp;amp;device=5&lt;br /&gt;
&lt;br /&gt;
This renames or deletes a device.  Use action=rename or action=delete.  For rename, you can optionally assign a room by either passing either the ID or the name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---old---&lt;br /&gt;
This returns all the XML with all the UPNP device description documents.  Use: http://ipaddress:3480/data_request?id=device&amp;amp;output_format=xml&amp;amp;DeviceNum=x or &amp;amp;UDN=y to narrow it down.  Then when you see the service URL's, like &amp;lt;SCPDURL&amp;gt;/luvd/S_HVAC_UserOperatingMode1.xml&amp;lt;/SCPDURL&amp;gt;, you can view them with: http://ipaddress:3480/luvd/S_HVAC_UserOperatingMode1.xml&lt;br /&gt;
---end old---&lt;br /&gt;
&lt;br /&gt;
==scene==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=record  &lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=pause&amp;amp;seconds=y&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=stoprecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=listrecord&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=deleterecord&amp;amp;number=x&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=saverecord&amp;amp;name=whatever&amp;amp;room=X&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=rename&amp;amp;scene=5&amp;amp;name=Chandalier&amp;amp;room=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=create&amp;amp;json=[valid json data]&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=list&amp;amp;scene=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a scene depending on the action.&lt;br /&gt;
&lt;br /&gt;
Recording a scene means whatever actions come in after sending the 'record' will be saved into an internal buffer.  listrecord shows what's recorded so far.  pause adds a pause.  deleterecord deletes some action in the internal buffer.  When deleting, for number=x, use the same 'id' in listrecord.  saverecord takes the internal buffer, the recorded macro, and saves it as an actual scene.&lt;br /&gt;
&lt;br /&gt;
To create a scene by hand, rather than recording it, use 'create'.  When using the 'create' command json must be valid JSON for a scene as documented in [[Scene_Syntax]].  The name, room and optional id (if you're overwriting an existing scene) are passed in the json, so nothing is on the command line except the json.  Because the json data can be long it is recommended to send it as an http POST instead of GET with the data passed with the name &amp;quot;json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
list returns the JSON data for an existing scene.&lt;br /&gt;
&lt;br /&gt;
==room==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=create&amp;amp;name=Kitchen&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=room&amp;amp;action=rename&amp;amp;room=5&amp;amp;name=Garage&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=scene&amp;amp;action=delete&amp;amp;room=5&lt;br /&gt;
&lt;br /&gt;
This creates, renames, or deletes a room depending on the action.  To rename or delete a room you must pass the room id for the room=.&lt;br /&gt;
&lt;br /&gt;
==file==&lt;br /&gt;
&lt;br /&gt;
==lua==&lt;br /&gt;
&lt;br /&gt;
== action  ==&lt;br /&gt;
&lt;br /&gt;
Example: http://ipaddress:3480/data_request?id=action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=6&amp;amp;amp;serviceId=urn:upnp-org:serviceId:SwitchPower1&amp;amp;amp;action=SetTarget&amp;amp;amp;newTargetValue=1 &lt;br /&gt;
&lt;br /&gt;
Sends a UPnP action. &lt;br /&gt;
&lt;br /&gt;
To run a scene, you send the action 'RunScene' like this:: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=&amp;amp;lt;SceneNum&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
==variableset==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableset&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&amp;amp;Value=1&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this sets a top-level json tag called &amp;quot;Variable&amp;quot; with the value.&lt;br /&gt;
&lt;br /&gt;
==variableget==&lt;br /&gt;
&lt;br /&gt;
http://ip:3480/data_request?id=variableget&amp;amp;DeviceNum=6&amp;amp;serviceId=urn:micasaverde-com:serviceId:DoorLock1&amp;amp;Variable=Status&lt;br /&gt;
&lt;br /&gt;
If you leave off the DeviceNum and serviceID, then this gets a top-level json tag called &amp;quot;Variable&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==reload==&lt;br /&gt;
&lt;br /&gt;
Resets the Luup engine with any new configuration settings.&lt;br /&gt;
&lt;br /&gt;
==alive==&lt;br /&gt;
&lt;br /&gt;
Return OK if the engine is running.&lt;br /&gt;
&lt;br /&gt;
==finddevice==&lt;br /&gt;
&lt;br /&gt;
Return the device id, UDN, device type of the first device that matches all the parameters passed on the URL: &amp;lt;tt&amp;gt;devtype&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ip&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==resync==&lt;br /&gt;
&lt;br /&gt;
ReSync's all the devices, rooms, users, sections with event servers and returns OK&lt;br /&gt;
&lt;br /&gt;
==wget==&lt;br /&gt;
&lt;br /&gt;
Returns the contents of the URL you pass in the &amp;quot;url&amp;quot; argument.  Optionally append &amp;quot;user&amp;quot; and &amp;quot;pass&amp;quot; arguments for http authentication, and &amp;quot;timeout&amp;quot; to specify the maximum time to wait in seconds.&lt;br /&gt;
&lt;br /&gt;
==iprequests==&lt;br /&gt;
&lt;br /&gt;
Returns the recent IP requests in order by most recent first, including information about devices in use and if the IP is blacklisted (ignored by the plug and play mechanism).  Optionally append &amp;quot;oldest&amp;quot; to specify the oldest IP request in seconds.&lt;br /&gt;
&lt;br /&gt;
==blacklistip==&lt;br /&gt;
&lt;br /&gt;
Append &amp;quot;ip&amp;quot; to the URL, and optionally &amp;quot;remove=1&amp;quot; to add (or remove) the IP to the blacklist so plug and play IP devices won't be added.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;Not implemented yet!&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==live_energy_usage==&lt;br /&gt;
&lt;br /&gt;
For backward compatibility it reports current energy usage in a tab delimited format&lt;br /&gt;
&lt;br /&gt;
== request_image ==&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt;NOTE:&amp;lt;/span&amp;gt;'''&amp;lt;span style=&amp;quot;color: rgb(255, 0, 0);&amp;quot;&amp;gt; request_video is not implemented yet.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns an image from a camera. This fetches the image from the camera using the URL variable for the device. Pass arguments: &lt;br /&gt;
&lt;br /&gt;
 cam = the device id of the camera.  This is the only mandatory argument.&lt;br /&gt;
 res = optional: a resolution, which gets appended to the variable.  So passing &amp;quot;low&amp;quot; means the image from the URL_low variable will be returned.  If it doesn't exist it reverts to the standard URL or DirectStreamingURL &lt;br /&gt;
 timeout = optional: how long to wait for the image to be retrieved, or how long to retrieve video.  defaults to 10 seconds.&lt;br /&gt;
 url = optional: override the camera's default URL&lt;br /&gt;
 ip = optional: override the camera's default ip&lt;br /&gt;
 user or pass = optional: override the camera's default username/password&lt;br /&gt;
&lt;br /&gt;
==jobstatus==&lt;br /&gt;
&lt;br /&gt;
==invoke==&lt;br /&gt;
&lt;br /&gt;
==relay==&lt;br /&gt;
&lt;br /&gt;
This tells the system to setup a relay so that you can access a device on the home network from outside the home.  This is most commonly used to fetch streaming video from a camera, although it can actually be used for any IP device.  This takes either an 'ip' or 'device' argument.  If you pass a device, this is assumed to be a device ID, and the system will find the ip associated with that device.  Optionally pass a port argument for the port you want to be relayed.  Port 80 is assumed if none is specified.&lt;br /&gt;
&lt;br /&gt;
This request will return a 'server:port' which you can use externally to access the designated device.  The relay stays open for 15 minutes before closing, at which point you will need to open it again.&lt;br /&gt;
&lt;br /&gt;
So, assume you have a NAS device on the home network with the ip 192.168.1.55 and the NAS runs a configuration web page on port 80.  You could access it by doing this:&lt;br /&gt;
&lt;br /&gt;
data_request?ip=192.168.1.55&amp;amp;port=80&lt;br /&gt;
&lt;br /&gt;
and if the response is: &amp;quot;someserver:20202&amp;quot;, then for 15 minutes, &amp;quot;http://someserver:20202&amp;quot; will be the NAS's configuration page.&lt;br /&gt;
&lt;br /&gt;
If you want to access a camera, device #5, then do this:&lt;br /&gt;
&lt;br /&gt;
data_request?device=5&lt;br /&gt;
&lt;br /&gt;
and if the response is &amp;quot;someserver:20211&amp;quot; and if the 'DirectStreamURL' variable (or 'streaming' in sdata) is &amp;quot;video.mpeg&amp;quot;, then for 15 minutes you can access the camera's video at: http://someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
Note that if the device, the camera in this case, has http authentication, you will need to pass this too.  So, if the user_data or sdata for the camera shows the user name is 'johndoe' and the password is 'john123', then you can view the video at: http://john:john123@someserver:20211/video.mpeg&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: For the 15 minutes while this relay is open, it will be open to anyone on the internet and public.  Therefore, for security, you may want to add to the data_request the argument externalip=x where x is the routable, external IP, such as 70.182.172.111, of the device that will be accessing the port.  This means that when the relay is open, a firewall will be set on the relay server so that incoming connections are only accepted from that ip address.&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Camera_Management_Server</id>
		<title>Camera Management Server</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Camera_Management_Server"/>
				<updated>2012-03-19T23:31:57Z</updated>
		
		<summary type="html">&lt;p&gt;Micasaverde: /* alert: Add an alert to the system */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Services]]&lt;br /&gt;
Certain cameras come with custom firmware so that they automatically connect to the MiOS camera management server (cms), creating a tunnel the cms can use to send commands to the camera and to act as a relay so users can view and control the camera when outside the home without having to change their firewall.&lt;br /&gt;
&lt;br /&gt;
Mios operates a camera server (&amp;quot;cs&amp;quot;) which is available at crX.mios.com (ie cr1.mios.com, cr2.mios.com, etc.). Cameras which are shipped with this custom firmware will automatically connect to the cs and report their Mac Address and IP address. Cs stores this in a database along with the external IP that the connection came in on.&lt;br /&gt;
&lt;br /&gt;
For most of the commands where you need to pass a username and password to the CMS server, you can also pass either a cam or a gateway and the corresponding hwkey if it's known.&lt;br /&gt;
&lt;br /&gt;
==Locating the camera==&lt;br /&gt;
&lt;br /&gt;
To get the list of all cameras and MiOS systems on your current home network, read this URL: http://sta1.mios.com/locator_json2.php which returns the list in JSON format.  To add to the list all cameras that are off the home network but which can be access remotely with a given username, add a ?username=x to the URL, such as http://sta1.mios.com/locator_json2.php?username=johndoe&lt;br /&gt;
&lt;br /&gt;
A camera will look like this:&lt;br /&gt;
&lt;br /&gt;
      {&lt;br /&gt;
            &amp;quot;serialNumber&amp;quot;: &amp;quot;554&amp;quot;,&lt;br /&gt;
            &amp;quot;Alive&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Good camera&amp;quot;,&lt;br /&gt;
            &amp;quot;mfr&amp;quot;: &amp;quot;Mios&amp;quot;,&lt;br /&gt;
            &amp;quot;ipAddress&amp;quot;: &amp;quot;192.168.2.27&amp;quot;,&lt;br /&gt;
            &amp;quot;category&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
            &amp;quot;subcategory&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;users&amp;quot;: &amp;quot;16782,3&amp;quot;,&lt;br /&gt;
            &amp;quot;ImageUrl_LR&amp;quot;: &amp;quot;img/snapshot.cgi?size=320x240&amp;amp;quality=4&amp;quot;,&lt;br /&gt;
            &amp;quot;MJpegUrl_LR&amp;quot;: &amp;quot;img/video.mjpeg&amp;quot;,&lt;br /&gt;
            &amp;quot;MP4Url_LR&amp;quot;: &amp;quot;img/video.asf&amp;quot;,&lt;br /&gt;
            &amp;quot;ImageUrl_HR&amp;quot;: &amp;quot;img/snapshot.cgi?size=640x480&amp;amp;quality=2&amp;quot;,&lt;br /&gt;
            &amp;quot;MJpegUrl_HR&amp;quot;: &amp;quot;img/video.mjpeg&amp;quot;,&lt;br /&gt;
            &amp;quot;MP4Url_HR&amp;quot;: &amp;quot;img/video.asf&amp;quot;,&lt;br /&gt;
            &amp;quot;CanRelay&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;Port&amp;quot;: &amp;quot;80&amp;quot;,&lt;br /&gt;
            &amp;quot;local_remote&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;relay_remote&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;active_server&amp;quot;: &amp;quot;cr1.mios.com&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
==Local vs remote access==&lt;br /&gt;
&lt;br /&gt;
In the Json data above, &amp;quot;active_server&amp;quot; tells you which Cs the camera connects to. So to view or control this camera connect to cr1.mios.com. If the camera is on the same network as the client, then ipAddress will have an ip. Otherwise there is no ipAddress. If the ipAddress is specified, then you can access the camera on the local network, without going through the relay server, by using ImageUrl, MJpegUrl and MP4Url tags to fetch a JPEG Image, MJPEG stream, or MP4 stream. _LR are low res verseions, _HR are high res. If CanRelay is 1, then this camera connects to the cs and you can also view the camera remotely using the Cs.&lt;br /&gt;
&lt;br /&gt;
==request_video: Request video from a camera==&lt;br /&gt;
&lt;br /&gt;
To view the video from the camera, open this URL:&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/request_video?cam=a&amp;amp;format=b&amp;amp;res=c&amp;amp;user=d&amp;amp;pass=e&lt;br /&gt;
&lt;br /&gt;
where a is the serial number of the camera, 554 in the above example, b is one of the defined constants below, c is the resolution and can be l or m or h, d and e are the username/password of the MiOS account the camera is paired with.&lt;br /&gt;
&lt;br /&gt;
This will return another URL.  If the viewer is on the same home network as the camera the URL will point directly to the camera.  Otherwise it will be a Url, for example http://209.160.41.93:80/relay_viewer?cam=554&amp;amp;pass=2024848122, which points to the Cs with a use-once token.  In this case the URL can only be used one time, and must be used within 1 minute of making the request.&lt;br /&gt;
&lt;br /&gt;
==request_image: Request image from a camera==&lt;br /&gt;
&lt;br /&gt;
To fetch a JPEG that is the current image from the camera, open this URL:&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/request_image?cam=a&amp;amp;res=b&amp;amp;user=c&amp;amp;pass=d&lt;br /&gt;
&lt;br /&gt;
where a is the serial number of the camera, 554 in the above example, b is &amp;quot;low&amp;quot; or &amp;quot;med&amp;quot; or &amp;quot;high&amp;quot; to indicate the resolution, c and d are the username/password of the MiOS account the camera is paired with.  Calling this with &amp;quot;low&amp;quot; is the right way to get at thumbnail.  This URL returns the JPEG image directly.&lt;br /&gt;
&lt;br /&gt;
==archive_video: Tells the cs to archive video from the camera ==&lt;br /&gt;
&lt;br /&gt;
This command causes the cs to capture video from the camera and add it to the video archive for the user.  The camera must be linked to a mios.com account.&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/archive_video?cam=a&amp;amp;preroll=b&amp;amp;duration=c&amp;amp;format=d&amp;amp;res=e&amp;amp;user=f&amp;amp;pass=g&lt;br /&gt;
&lt;br /&gt;
where a is the serial number of the camera, 554 in the above example, b is 0 or 1 where 1 means to also capture whatever pre-roll is available from the camera, c is how long in seconds to capture the video, d is one of the formats id's defined below, e is &amp;quot;low&amp;quot; or &amp;quot;med&amp;quot; or &amp;quot;high&amp;quot; to indicate the resolution, f and g are the username/password of the MiOS account the camera is paired with.&lt;br /&gt;
&lt;br /&gt;
The pre-roll is a given number of seconds at a given resolution as specified in the &amp;quot;config&amp;quot; command.&lt;br /&gt;
&lt;br /&gt;
==archive_image: Tells the cs to archive an image from the camera ==&lt;br /&gt;
&lt;br /&gt;
This is like archive_video except it stores a single image.  If retimg=1 then the image being archived will also be returned by the Url, just like request_image.&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/archive_image?cam=a&amp;amp;res=b&amp;amp;user=c&amp;amp;pass=d&amp;amp;retimg=e&lt;br /&gt;
&lt;br /&gt;
==list_alerts: The cs returns a list of archived alerts, both system alerts and images and video  ==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/list_alerts?cam=a&amp;amp;gateway=b&amp;amp;unread=1&amp;amp;type=c&amp;amp;source=d&amp;amp;format=e&amp;amp;device=f&amp;amp;count=g&amp;amp;start=h&amp;amp;before=i&amp;amp;after=j&amp;amp;user=k&amp;amp;pass=l&amp;amp;userevt=m&lt;br /&gt;
&lt;br /&gt;
This returns a list of archives in JSON format as follows:&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;records&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 192817,&lt;br /&gt;
            &amp;quot;gateway&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;cam&amp;quot;: &amp;quot;554&amp;quot;,&lt;br /&gt;
            &amp;quot;user&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;notification&amp;quot;: &amp;quot;1827&amp;quot;,&lt;br /&gt;
            &amp;quot;device&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;timestamp&amp;quot;: &amp;quot;18217271&amp;quot;,&lt;br /&gt;
            &amp;quot;date&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;expiration&amp;quot;: &amp;quot;18217271&amp;quot;,&lt;br /&gt;
            &amp;quot;read&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;source&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;format&amp;quot;: &amp;quot;jpg&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;192.168.2.27&amp;quot;,&lt;br /&gt;
            &amp;quot;locked&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
            &amp;quot;size&amp;quot;: &amp;quot;32728&amp;quot;,&lt;br /&gt;
            &amp;quot;code&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;value&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Camera Image&amp;quot;,&lt;br /&gt;
            &amp;quot;key&amp;quot;: &amp;quot;1278&amp;quot;,&lt;br /&gt;
            &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
The arguments are as follows:&lt;br /&gt;
&lt;br /&gt;
cam=If specified this is the id of the camera(s).  Only alerts from this camera(s) are included.  Multiple cameras should be comma separated.  Or specify * for all cameras the user has access to.&lt;br /&gt;
&lt;br /&gt;
gateway=If specified this is of a gateway(s).  Only alerts from this gateway(s) are included.  Multiple cameras should be comma separated.  Or specify * for all gateways the user has access to.&lt;br /&gt;
&lt;br /&gt;
user=See note below.&lt;br /&gt;
&lt;br /&gt;
NOTE: If neither cam nor gateway is specified, only alerts from the user which is passed for validation are included, such as login events.  If a cam(s) and or gateways(s) are specified, then user alerts as well as gateway/cam alerts are included.  If you only want gateway/cam alerts, add a user=0.  This will exclude user events.  So gateway=1,3&amp;amp;cam=* will include alerts from gateways #1 and 3, as well as all cameras, plus the users alerts.  Adding user=0 will exclude the users alerts.  If user=0 is specified without any gateway or cam no records are returned.  Note that alerts from a gateway/cam will not be included if the gateway/cam is not already paired to the user's account.&lt;br /&gt;
&lt;br /&gt;
unread=If this is a '1' only alerts that haven't been read yet are included&lt;br /&gt;
&lt;br /&gt;
type=Only alerts of this type are included (see alert types below)&lt;br /&gt;
&lt;br /&gt;
source=Only alerts from this source are included (see source types below)&lt;br /&gt;
&lt;br /&gt;
format=Only alerts containing files of this format are included (eg mp4, jpg, mjpeg).&lt;br /&gt;
&lt;br /&gt;
device=If a gateway is specified, only alerts from this device id on the gateway are included.&lt;br /&gt;
&lt;br /&gt;
count=This many rows are included&lt;br /&gt;
&lt;br /&gt;
start=Starting with this row number&lt;br /&gt;
&lt;br /&gt;
before= / after= a date range as a unix timestamp (ie an integer in UTC time).  You cannot use local time because some devices, like cameras, don't have a clock/timezone setting, so the times are universal timestamps applied by the server and not local times on the device.&lt;br /&gt;
&lt;br /&gt;
The return data in json is as follows:&lt;br /&gt;
&lt;br /&gt;
id=A numeric id of the alert&lt;br /&gt;
&lt;br /&gt;
gateway=The id of the gateway that generated the alert, if any&lt;br /&gt;
&lt;br /&gt;
cam=The id of the camera that generated the alert, if any&lt;br /&gt;
&lt;br /&gt;
user=The id of the user that generated the alert, if any&lt;br /&gt;
&lt;br /&gt;
notification=If user(s) were sent a notification of the alert (SMS, email) this is the id of the notification attempt(s)&lt;br /&gt;
&lt;br /&gt;
device=If a device on a gateway generated the alert this is the device id&lt;br /&gt;
&lt;br /&gt;
timestamp=The date when the alert was received as a unix timestamp&lt;br /&gt;
&lt;br /&gt;
date=The date according to the gateway, specified in local time as yyyy-mm-dd hh:mm:ss&lt;br /&gt;
&lt;br /&gt;
read=The date when the alert was read by the user as a unix timestamp&lt;br /&gt;
&lt;br /&gt;
expiration=The date when the alert will be automatically deleted as a unix timestamp&lt;br /&gt;
&lt;br /&gt;
type=The type of alert: 1=Image (a camera sent an image), 2=Video (a camera sent a video clip), 3=Trigger (a user-created trigger was fired), 4=Variable (a device changed state, such as a door was unlocked, a user code entered, a sensor tripped), 5=Login (a user logged into the portal), 6=Gateway Connected (a gateway came online)&lt;br /&gt;
&lt;br /&gt;
source=What caused the alert to be generated: 1=User (e.g. user hit 'record' button or otherwise initiated the alert), 2=Timer (an automatic timer generated it), 3=Trigger (a user-created trigger), 4=Variable (some device changed state)&lt;br /&gt;
&lt;br /&gt;
format=If there's a file associated with the alert, this is the extension, such as mpg, jpg, mjpeg&lt;br /&gt;
&lt;br /&gt;
ip=The IP that sent the alert&lt;br /&gt;
&lt;br /&gt;
locked=If 1 the alert will not automatically delete on the expiration&lt;br /&gt;
&lt;br /&gt;
size=If there's a file associated with the alert, this is the size of the file&lt;br /&gt;
&lt;br /&gt;
code and value=These depend on the type of alert.  For Variables 'code' is the name of the variable (state) that changed and value is the new value.&lt;br /&gt;
&lt;br /&gt;
description=A description for the alert.  For triggers this is the user-defined trigger name.&lt;br /&gt;
&lt;br /&gt;
key=A unique, random value for each alert.  When you need to modify an alert you will pass back the key to confirm you are authorized.&lt;br /&gt;
&lt;br /&gt;
comments=Comments which the user has associated with the alert.&lt;br /&gt;
&lt;br /&gt;
If a file is associated with the alert, see the fetch_archive call.&lt;br /&gt;
&lt;br /&gt;
==fetch_alert: Return the details about an alert==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/fetch_alert?id=a&amp;amp;key=b&lt;br /&gt;
&lt;br /&gt;
Pass in the key from the alert (see list_alerts) as b and the alert id as a.  This returns the details about the alert, including any notification attempts, as follows.  Note the status codes for contacts and attempts are in the defined constants section:&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;id&amp;quot;: 192890,&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;aaronb&amp;quot;,&lt;br /&gt;
    &amp;quot;contacts&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 10,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;destination&amp;quot;: &amp;quot;john@gmail.com&amp;quot;,&lt;br /&gt;
            &amp;quot;numattempts&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;status&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;contents&amp;quot;: &amp;quot;200820:\r\n=\r\nserial:-\r\n&amp;quot;,&lt;br /&gt;
            &amp;quot;username&amp;quot;: &amp;quot;john&amp;quot;,&lt;br /&gt;
            &amp;quot;attempts&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;timestamp&amp;quot;: 182821717,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;notes&amp;quot;: &amp;quot;busy&amp;quot;&lt;br /&gt;
                },&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;timestamp&amp;quot;: 1812717,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
                    &amp;quot;notes&amp;quot;: &amp;quot;complete&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
            ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 20,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;destination&amp;quot;: &amp;quot;+1310-555-0800&amp;quot;,&lt;br /&gt;
            &amp;quot;numattempts&amp;quot;: 0,&lt;br /&gt;
            &amp;quot;status&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;contents&amp;quot;: &amp;quot;200820:\r\n=\r\nserial:-\r\n&amp;quot;,&lt;br /&gt;
            &amp;quot;username&amp;quot;: &amp;quot;john&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==alter_alert: Alert data in the alert==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/alter_alert?id=a&amp;amp;key=b&amp;amp;read=c&amp;amp;deleted=d&amp;amp;locked=e&amp;amp;comments=f&lt;br /&gt;
&lt;br /&gt;
This will change the alert 'a'.  Pass in the key from the alert (see list_alerts) as b.  Optionally pass in a unix timestamp for c to indicate if it's read, or 0 to indicate it is unread.  Pass in 0 or 1 for deleted or locked (d or e) to indicate if the record should be deleted, or if it's locked, meaning it won't be deleted after the expiration.  Comments will update the user comments for an alert.  Don't forget to properly URL encode the comments.  read, deleted, locked and comments are all optional, although at least one must be specified.&lt;br /&gt;
&lt;br /&gt;
==alert: Add an alert to the system==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/alert?PK_AccessPoint=a&amp;amp;PK_Accessory=b&amp;amp;EK_User=c&amp;amp;HW_Key=d&amp;amp;user=e&amp;amp;pass=f&amp;amp;DeviceID=g&amp;amp;LocalDate=h&amp;amp;AlertType=i&amp;amp;SourceType=j&amp;amp;Argument=k&amp;amp;Format=l&amp;amp;Code=m&amp;amp;Value=n&amp;amp;Description=o&amp;amp;Users=p&amp;amp;Expiration=q&lt;br /&gt;
&lt;br /&gt;
Expiration should be a unix timestamp&lt;br /&gt;
&lt;br /&gt;
==fetch_archive: The cs returns an archived image or video  ==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/fetch_archive?id=a&amp;amp;user=b&amp;amp;pass=c&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/fetch_archive?id=a&amp;amp;key=b&lt;br /&gt;
&lt;br /&gt;
==move_camera: Tells the cs to move the camera ==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/move_camera?cam=a&amp;amp;dir=b&amp;amp;user=c&amp;amp;pass=d&lt;br /&gt;
&lt;br /&gt;
Where dir can be &amp;quot;up&amp;quot;, &amp;quot;down&amp;quot;, &amp;quot;left&amp;quot;, &amp;quot;right&amp;quot;, &amp;quot;in&amp;quot; or &amp;quot;out&amp;quot; (for zoom).&lt;br /&gt;
&lt;br /&gt;
==send: Sends a URL to the camera==&lt;br /&gt;
&lt;br /&gt;
https://cr1.mios.com/send?cam=a&amp;amp;user=b&amp;amp;pass=c&amp;amp;url=d&lt;br /&gt;
&lt;br /&gt;
Everything after the url= is sent to the camera.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
https://cr1.mios.com/send?cam=37117&amp;amp;user=johndoe&amp;amp;pass=mypassword123&amp;amp;url=/adm/set_group.cgi?group=VIDEO&amp;amp;exposure=1&amp;amp;sharpness=7&lt;br /&gt;
&lt;br /&gt;
Refer to the camera's manual for specific settings&lt;br /&gt;
&lt;br /&gt;
==defined constants==&lt;br /&gt;
&lt;br /&gt;
Here are the defined constants for format, resolution, etc., and the extensions that correspond to formats:&lt;br /&gt;
&lt;br /&gt;
 #define ALERT_IMAGE                             1&lt;br /&gt;
 #define ALERT_VIDEO                             2&lt;br /&gt;
 #define ALERT_TRIGGER                   3&lt;br /&gt;
 #define ALERT_VARIABLE                  4&lt;br /&gt;
 #define ALERT_LOGON                             5&lt;br /&gt;
 #define ALERT_GATEWAY_CONNECTED 6  // If the external IP changes or if it's been&amp;gt;  24 hours since last report&lt;br /&gt;
&lt;br /&gt;
  #define FORMAT_JPEG    1&lt;br /&gt;
  #define FORMAT_MJPEG    2&lt;br /&gt;
  #define FORMAT_MP4    3&lt;br /&gt;
  &lt;br /&gt;
  #define EXT_JPEG    &amp;quot;jpg&amp;quot;&lt;br /&gt;
  #define EXT_MJPEG    &amp;quot;mjpg&amp;quot;&lt;br /&gt;
  #define EXT_MP4      &amp;quot;mp4&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
  #define SOURCE_USER    1&lt;br /&gt;
  #define SOURCE_TIMER  2&lt;br /&gt;
  #define SOURCE_TRIGGER  3&lt;br /&gt;
  #define SOURCE_VARIABLE 4&lt;br /&gt;
&lt;br /&gt;
  #define CONTACT_STATUS_SUCCESS	0&lt;br /&gt;
  #define CONTACT_STATUS_PROCESSING	1&lt;br /&gt;
  #define CONTACT_STATUS_FAILED		2&lt;br /&gt;
  #define CONTACT_STATUS_RETRY		3&lt;br /&gt;
&lt;br /&gt;
  #define ATTEMPT_STATUS_SUCCESS	0&lt;br /&gt;
  #define ATTEMPT_STATUS_PROCESSING	1&lt;br /&gt;
  #define ATTEMPT_STATUS_FAILED		2&lt;/div&gt;</summary>
		<author><name>Micasaverde</name></author>	</entry>

	</feed>