<?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=Andreimios</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=Andreimios"/>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Special:Contributions/Andreimios"/>
		<updated>2026-06-03T02:51:21Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.19.8</generator>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Notes</id>
		<title>UI Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Notes"/>
				<updated>2015-07-03T12:27:33Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* lu_status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
Here is some general information about getting information to display in a user interface:&lt;br /&gt;
&lt;br /&gt;
== UPnP messaging system  ==&lt;br /&gt;
&lt;br /&gt;
Vera uses UPnP for all the messaging, such as turning lights on and off.  So Vera translates Z-Wave, Insteon, infrared codes, etc., into UPnP actions. If you have already implemented a UPnP stack and can send properly formated UPnP SOAP/XML requests, you can control everything using standard UPnP action invocation. If you did not, Vera provides a simple HTTP GET interface as well, which is discussed below.&lt;br /&gt;
&lt;br /&gt;
In a nutshell UPnP works like this: You have UPnP devices, which are things that can be controlled and can report their state, like a light switch.  And you have UPnP Control Points, which are the things that let a user control UPnP devices, like a touch-screen web pad.  The Control Point does this by a) reading the device and descriptions for the UPnP device to see what it can do, and b) invoking actions on the UPnP device (ie telling it to do something), and c) reading and setting variables for the device which describe the current state and/or configuration settings for the device.&lt;br /&gt;
&lt;br /&gt;
A UPnP device is defined in an XML document called a device description document.  To see one, in Vera's setup UI, go to Devices, Luup plugins, Luup Files, and click 'view' file next to D_BinaryLight1.xml.  Use Firefox since it has a built-in XML viewer.  Notice the tag: &amp;lt;deviceType&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/deviceType&amp;gt;.  This defines the type of device, namely an on/off light switch, which is what you use to know how to represent this device to a user.  A device optionally implements one or more services.  In this case the services: urn:upnp-org:serviceId:SwitchPower1, urn:micasaverde-com:serviceId:EnergyMetering1 and urn:micasaverde-com:serviceId:HaDevice1.&lt;br /&gt;
&lt;br /&gt;
A service is a collection of actions which a device implement and which you can invoke from a UPnP Control Point, as well as a collection of variables which always have a current value.  The variables describe the current state of the device and/or configuration settings.  View the file S_SwitchPower1.xml to see a service.  For example, the device urn:schemas-upnp-org:device:BinaryLight:1 implements the service urn:upnp-org:serviceId:SwitchPower1, which has the action SetTarget, which is how you turn the light on and off.  The action takes a single argument newTargetValue which can be 0 to turn the light off and 1 to turn it on.  The service also has the variable Status which is 0 or 1 depending on whether the light is currently on or off.&lt;br /&gt;
&lt;br /&gt;
If you open the device description for a dimmable light D_DimmableLight1.xml you'll see that it implements the same service S_SwitchPower1.xml, since you can still turn it on and off, and it also implements the service urn:upnp-org:serviceId:Dimming1, which has an action to set the dim level (SetLoadLevelTarget).&lt;br /&gt;
&lt;br /&gt;
To test UPnP calls you can use the Intel Device Spy utility available [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology_v2.zip here].  It should pick up Vera, show you all the devices, like light switches, thermostats, etc., let you expand the services and see the actions and variables.  Click an action, like SetTarget, to specify the arguments and click 'Invoke' to run the action, such as turning on and off the light.&lt;br /&gt;
&lt;br /&gt;
== JSON vs. XML ==&lt;br /&gt;
&lt;br /&gt;
The native UPnP protocol uses XML/SOAP.  But there are also several times you will request data from Vera that has nothing to do with the UPnP spec.  These will be done with data_request's as explained below, such as user_data, lu_status, etc.  Internally Vera uses JSON as the native format, but Vera can convert to XML (details follow).  In general when you want to view data in a human readable format, such as the device list, it's easiest to use the Firefox browser, and request Vera convert the data to XML.  Firefox has a nice browser to display XML in human readable format.  If you want to make the JSON data nicely formatted, you can use the web site jsonlint.com.  In a UI application which will request data regularly from Vera we recommend retrieving everything in JSON format, not XML, because Vera's CPU is not that powerful and so continuous requests of data in XML format will cause a lot of CPU time to be devoted to converting JSON into XML.&lt;br /&gt;
&lt;br /&gt;
== Finding Vera on the local network  ==&lt;br /&gt;
&lt;br /&gt;
You can find Vera by using the traditional UPnP discovery process, or you can retrieve this URL:&amp;lt;br&amp;gt;'''https://sta1.mios.com/locator_json.php?username=xxx''' where the username=xxx is optional, but, if specified, it will report all systems that mios.com user xxx can report whether local or remote, and without the username=xxx it only shows the Vera's on the user's local home network.&lt;br /&gt;
&lt;br /&gt;
Each Vera, when it boots up, reports its internal IP address to the central mios.com server, which tracks this along with the external IP address. '''locator.php''' shows all serial numbers and internal network IP addresses on the same external IP. For example, if '''https://sta1.mios.com/locator_json.php?username=xxx'''.&lt;br /&gt;
&lt;br /&gt;
== The HTTP interface  ==&lt;br /&gt;
&lt;br /&gt;
Vera listens on port 3480. Vera responds to UPnP actions the normal way, or by making simple HTTP requests. For example, to turn on a light you can either send the UPnP action &amp;quot;SetTarget&amp;quot; to the device using the normal UPnP mechanism, or you can simply put this URL in your web browser, or with wget, or similar: &lt;br /&gt;
&lt;br /&gt;
http://[ipadress]:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
That URL will return the same results of the action as using the normal UPnP architecture. The '''output_format=xml''' on the URL means the data returned should be in XML format. You can instead use '''output_format=json'''&lt;br /&gt;
&lt;br /&gt;
The service ID's, actions, and arguments are all defined by the UPnP forum.  A list of ratified UPnP devices and services is available on the [http://www.upnp.org UPnP Forum].  Mi Casa Verde added its own custom devices and services when there was no existing UPnP standard.  A list of these can be found in the [[Luup_UPNP_Files]] header files.&lt;br /&gt;
&lt;br /&gt;
== Getting the system configuration  ==&lt;br /&gt;
&lt;br /&gt;
Either use the UPnP service/action:&amp;lt;br&amp;gt; '''urn:micasaverde-com:serviceId:HomeAutomationGateway1/GetUserData''' &lt;br /&gt;
&lt;br /&gt;
or use the built-in request: &lt;br /&gt;
&lt;br /&gt;
'''http://ipaddress:3480/data_request?id=user_data2&amp;amp;amp;output_format=json''' (or xml) &lt;br /&gt;
&lt;br /&gt;
This returns the system configuration file for Vera. It's assumed you understand the way Vera categorizes devices with Rooms, Devices, Scenes, etc. When creating a user interface for controlling Vera only, like on a mobile phone, most of the tags can be ignored, since usually you just need the list of rooms and devices.&lt;br /&gt;
&lt;br /&gt;
== Accessing Vera remotely through the mios server ==&lt;br /&gt;
&lt;br /&gt;
Native UPnP only works on a local area home network, and cannot be used over the Internet.  The mios server provides a secure way to remotely access and control your Vera system using the HTTP interface without having to make any substantial changes to the UI.  Everything you can do locally with Vera on port 3480, you can do remotely with mios using the exact same syntax.  You only need to ask the user for his username and password and pass them on the URL to the remote access server, along with the serial number of the unit (ie like 12345).  For example, the above user_data is the syntax for local access on a home network.  To retrieve the same URL over the internet with mios use:&lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/demovera/myvera123/12345/data_request?id=lu_status&amp;amp;output_format=json (or use fwd1.mios.com)&lt;br /&gt;
&lt;br /&gt;
assuming demovera is the username and myvera123 is the password that the user chose setting up his mios.com account.  Note that since the request is https, the username and password are encrypted because https encrypts the URL's as well as the contents of the page.&lt;br /&gt;
&lt;br /&gt;
== Building a control-only UI for Vera  ==&lt;br /&gt;
&lt;br /&gt;
If you just want to control Vera, and not modify the configuration, such as with a cell phone interface or web pad, the flow might possibly work like this: &lt;br /&gt;
&lt;br /&gt;
'''1)''' For the initial setup, you need to ask whether the user wants to (a)&amp;amp;nbsp;access Vera remotely with the mios service, and if so, get the user's username/password; or (b) access Vera directly on the home network. You can use locator.php to show the Vera on the home network. You might want to do an auto-detect. For example, you could use locator.php to see if Vera exists locally, and if not, prompt the user for a mios username and password. You can use locator.php and pass the username to get the serial number and internal IP, and then automatically switch to direct access if locator.php (without the username) indicates that serial number is found on the local network. This would allow the user to automatically switch between local access with Wi-Fi (which is much faster of course) and remote access with mios and the mobile phone network.  Or just ask for his mios username and show him all the Vera's he can control, either local or remote.&lt;br /&gt;
&lt;br /&gt;
'''2)''' Once the connection is established, retrieve the list of rooms, scenes, and devices from Vera (see '''user_data''' below). You can cache this data locally so you don't need to retrieve it and parse it over and over.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Present the user with the rooms, scenes, devices.  In Vera's UI's we show first the rooms and then let the user pick a device or scene in the room.  However this data could be presented graphically, such as on a floorplan.  Your UI can have Vera store extra tags and data in the configuration database (ie user_data) to store things like coordinates for icons, outlines or rooms and so on.&lt;br /&gt;
&lt;br /&gt;
'''4)''' If the user picks a scene you can run the scene with the following URL, passing the scene number as '''x''', and it will return an OK if it went okay: &lt;br /&gt;
&lt;br /&gt;
http://127.0.0.1:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=x &lt;br /&gt;
&lt;br /&gt;
'''5)''' If the user picks a device, you use the category which is contained in the user_data to determine what type of controls to present the user. (See [[Luup UPNP Files]] for a list of the categories.) When the user chooses an action, you can send it like this: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
For a list of common actions and device types see: [[Luup CP Mandatory Types]] &lt;br /&gt;
&lt;br /&gt;
Some actions return immediately with an 'OK'. Other jobs may take time to complete and are processed asynchronously.  For these asynchronous jobs you will get a job ID back.  There are several ways to present this to the user.  One possibility is to do what Vera does in the UI, namely to use '''lu_status '''(explained next) to find all active jobs and to put a 'job' icon next to each device to indicate the progress of the job. In this way the user isn't tracking a particular job ''per se'', but just has visual feedback that a device is busy, and if the job icon(s) turn green, that everything went through okay. You could instead track the action individually using the job number that is returned, or use some other method, like making the icon for the device appear animated while it's busy, and turn green or red if the last command succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
'''6)''' Periodically poll the system with '''lu_status''' (explained below), like this: &lt;br /&gt;
&lt;br /&gt;
http://ipaddress:3480/data_request?id=lu_status&amp;amp;amp;output_format=json &lt;br /&gt;
&lt;br /&gt;
That returns the current values of the UPnP variables, which you can use to show the user current status. For example, if the variable Status is 1 for a switch, you can show the 'on' button in a selected state, while 0 shows it in an 'off' state. '''lu_status''' also shows any active jobs for a device.&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
&lt;br /&gt;
The user_data is the main configuration file that Vera uses to store all the rooms, devices, scenes, timers, events, users, and any other data about the system.  You should request the user_data to get whatever data you need to present to the user, at a minimum, for example, you'll need the list of devices, their descriptions, and the categories (light switch, thermostat, etc.).  You'll also want the list of scenes to present the user.  To fetch the current user_data from Vera use the user_data request, like this:&lt;br /&gt;
&lt;br /&gt;
Returns JSON (preferred native format):&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&lt;br /&gt;
&lt;br /&gt;
Returns XML:&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
You can also add a 'DataVersion=TimeStamp' parameter to the URL. It the data has changed since the TimeStamp, all the data is returned. If the data has not changed since the TimeStamp, Vera will return a page with the text 'NO_CHANGES':&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
The user_data contains the state for all the devices.  For example this indicates that the device id #17, called &amp;quot;Switch&amp;quot; is turned off (ie service SwitchPower1, variable Status is 0)&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 17,&lt;br /&gt;
            &amp;quot;category&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;room&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Switch&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;mac&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: &amp;quot;0&amp;quot; &lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
     ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
{{Warning|On UI7 build lu_sdata and lu_status have been deprecated, and you should use &amp;quot;status&amp;quot; instead.}}&lt;br /&gt;
&lt;br /&gt;
==lu_status==&lt;br /&gt;
The UPnP variables describe the state of the devices according to the UPnP specs. When the variables change that information needs to be shown to the user, eg change a Switch icon from off to on. If you are interfacing with Vera using the UPnP stack, you can subscribe to the device's events to receive notifications automatically when a device's state changes. However if you're using the web interface you will need to poll using status request.&lt;br /&gt;
&lt;br /&gt;
Call lu_status request like so:&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=status&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=status&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The returned document contains four sets of information, which constantly change to reflect the current status:&lt;br /&gt;
* root attributes including DataVersion, which is the status timestamp, plus other attributes such as LoadTime &lt;br /&gt;
*the state of the system initialization, such as initialization of the plugin modules.&lt;br /&gt;
*a '''subset''' of the user_data that represents the current state of the device's UPnP variables&lt;br /&gt;
*the status of any active or recent '''jobs''', such as if a light was successfully turned off&lt;br /&gt;
&lt;br /&gt;
===Tracking status changes===&lt;br /&gt;
If you call lu_status without passing a DataVersion on the URL, you will get the current value of all the UPnP variables for a device.  Note that most of the UPnP variables do not ever change.  For example, with a light switch, only the variable &amp;quot;SwitchPower:Status&amp;quot; changes, as the switch is turned off and on.  There are many other variables, like &amp;quot;Capabilities&amp;quot; which are simply configuration data or settings the user modified.  If you pass &amp;amp;DataVersion=1 on the URL, you will only see the UPnP variables which have changed since the Luup engine started.  So, if you parse the initial UPnP variables when you first call user_data, you can call lu_status with DataVersion=1.  Once you call lu_status the first time, store the DataVersion and on subsequent calls pass it on the URL and you will only get the UPnP variables which have changed since that last DataVersion.  Regardless, you will also get the current state of jobs and system initialization.&lt;br /&gt;
&lt;br /&gt;
On subsequent calls to lu_status, you should also pass back in the LoadTime which you received on the prior call.&lt;br /&gt;
&lt;br /&gt;
===Controlling the poll timing===&lt;br /&gt;
You can also pass in a Timeout value, which means the call will block for up to that many seconds if nothing has changed, and will return immediately when something does.  This way you can have infrequent polling, say every 60 seconds by putting a Timeout value of 60, but your UI will be immediately responsive since, when something changes, it returns immediately.  You can also add a MinimumDelay, which means that the call will wait for at least that many milliseconds.  This is advisable so that in the event there are lots of continuous changes, such as a scene turning off many lights, you won't have lu_status calls returning non-stop consuming all the resources on both the Vera and the UI.&lt;br /&gt;
&lt;br /&gt;
===Startup status===&lt;br /&gt;
The section with the initialization tasks is shown in the startup tag as shown:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;startup&amp;quot;: {&lt;br /&gt;
        &amp;quot;tasks&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: 0,&lt;br /&gt;
                &amp;quot;status&amp;quot;: 2,&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;ZWave&amp;quot;,&lt;br /&gt;
                &amp;quot;comments&amp;quot;: &amp;quot;No Z-Wave&amp;quot; &lt;br /&gt;
            },&lt;br /&gt;
&lt;br /&gt;
The startup tasks begin whenever the Luup engine is reset, such as after the user makes a configuration change.  Ever plugin and module in the Luup engine does a startup sequence.  The id is not really important.  The status numbers are the same as for jobs, so 2 means the module failed to startup.  The 'Type' is what you can use to key off of to know which module is being reported, such as &amp;quot;ZWave&amp;quot;, and comments are just notes indicating the current state.  For example, &amp;quot;No Z-Wave&amp;quot; means there's no Z-Wave dongle connected.&lt;br /&gt;
&lt;br /&gt;
Once all the plugins have been initialized successfully the startup section will disappear completely from lu_status.&lt;br /&gt;
&lt;br /&gt;
Note that lu_status also returns UserData_DataVersion, which is the dataversion from user_data.  That way you don't need to poll user_data in parallel.  Simply retrieve the user_data one time at startup, then poll lu_status, and, if UserData_DataVersion is different from the previous user_data you retrieved, then download user_data again.&lt;br /&gt;
&lt;br /&gt;
Some notes on building a full replacement, including configuration, are available here [[UI_Notes_Replacement]], however the syntax is not up to date with the Luup architecture.&lt;br /&gt;
&lt;br /&gt;
===Job status===&lt;br /&gt;
The jobs for a device will look like this:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;Jobs&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;name&amp;quot;: &amp;quot;job#1 :getnodes (0x00D068F0) P:10 S:4&amp;quot;,&lt;br /&gt;
                    &amp;quot;icon&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;4&amp;quot; &lt;br /&gt;
                } &lt;br /&gt;
            ] &lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
The id is the job id number.  When you run an action, like turning on a light, if it happens asynchronously, you'll get a job id number.  All pending jobs for a device are shown by their id number.  The name is just an internal name for the job.  Icon is an optional keyword to indicate what sort of icon should be shown to the user.  For example, 'getnodes' has no icon, meaning this type of job is generally not of interest to a user.  If the icon was 'ON' or 'OFF' that would mean this job is busy turning on or off a light.  Comments is notes about the job, if any.  This may be shown to a user in a tool tip or similar, but is generally more technical than users would care to know.  The status indicates the current state of the job, as shown:&lt;br /&gt;
&lt;br /&gt;
*job_None=-1,  // no icon&lt;br /&gt;
*job_WaitingToStart=0,  // gray icon&lt;br /&gt;
*job_InProgress=1,  // blue icon&lt;br /&gt;
*job_Error=2,  // red icon&lt;br /&gt;
*job_Aborted=3,  // red icon&lt;br /&gt;
*job_Done=4,  // green icon&lt;br /&gt;
*job_WaitingForCallback=5  // blue icon - Special case used in certain derived classes&lt;br /&gt;
&lt;br /&gt;
If the status is 0, this means the job is queued but hasn't started.  If it's 1 or 5 the job is being executed right now.  Generally both 1 and 5 are presented to the user the same way as a 'busy', although technically 1 means Vera is actively talking to the device, and 5 means Vera is waiting for a reply from the device.  Status codes 2, 3 and 4 mean the job has finished.  4 means the job went ok, and both 2 and 3 mean it failed.  Technically 3 means the job was aborted by another job or an external process, like a user cancelling it, while 2 means it failed due to a problem talking to the device.  In both cases this is usually presented the user the same way, as a failure.&lt;br /&gt;
&lt;br /&gt;
== Categories and device types ==&lt;br /&gt;
&lt;br /&gt;
The values used in user_data to determine the types of devices are in [[Luup_UPNP_Files]].  In general you can use the category instead of the devicetype since it's an integer and is thus faster to compare:&lt;br /&gt;
&lt;br /&gt;
== pseudo-code for a UI ==&lt;br /&gt;
&lt;br /&gt;
Here is some pseudo code to show how the polling mechanism should be properly implemented.  The parsing code is, of course, unique to your UI, so placeholder function names are shown here, like FetchAndParse.  This shows the flow for handling the polling so you know you get the changes reported correctly.&lt;br /&gt;
&lt;br /&gt;
 variable int DataVersion_lustatus=0&lt;br /&gt;
 variable int LoadTime=0&lt;br /&gt;
 variable int DataVersion_userdata=0&lt;br /&gt;
&lt;br /&gt;
:START&lt;br /&gt;
  variable boolean FetchUserData=false;&lt;br /&gt;
  if( DataVersion_userdata==0 )  // If we're on the first loop and haven't retrieved user_data, do it and don't do an lu_status&lt;br /&gt;
    FetchUserData=true;&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
     while(true)&lt;br /&gt;
     {&lt;br /&gt;
         newdata = FetchAndParse(&amp;quot;lu_status&amp;amp;DataVersion=&amp;quot;+DataVersion_lustatus+&amp;quot;&amp;amp;LoadTime=&amp;quot;+LoadTime);&lt;br /&gt;
         if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
            break;  // If we got data, continue on and process it&lt;br /&gt;
        else&lt;br /&gt;
            Sleep 1; // If we didn't get anything, or if lu_status failed, just sleep 1 second and stay in the loop to try again&lt;br /&gt;
     } // End of while loop&lt;br /&gt;
&lt;br /&gt;
     if( newdata.UserData_DataVersion!=DataVersion_userdata )&lt;br /&gt;
     {&lt;br /&gt;
        FetchUserData=true;&lt;br /&gt;
     }&lt;br /&gt;
     else  // Only Parse if userdata is the same, otherwise we're going to reload user_data&lt;br /&gt;
     {&lt;br /&gt;
        ParseLuStatus();  // This won't run if user_data has changed&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
      }&lt;br /&gt;
  }  // end of else loop&lt;br /&gt;
&lt;br /&gt;
 if( FetchUserData==true )&lt;br /&gt;
{&lt;br /&gt;
   UI.HourglassAndSuspend(true); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
   newdata = FetchAndParse(&amp;quot;user_data2&amp;quot;);&lt;br /&gt;
    if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
    {&lt;br /&gt;
        ParseUserData();&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
         LoadTime=newdata.LoadTime&lt;br /&gt;
         DataVersion_userdata=newdata.DataVersion&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
       UI.DisplayError(&amp;quot;Failed to update data&amp;quot;); // Display in the info panel an error message that the user will see for 10 seconds or so&lt;br /&gt;
&lt;br /&gt;
   UI.HourglassAndSuspend(false); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Sleep 1; // We know we just parsed user_data or lu_status, so sleep before looping&lt;br /&gt;
goto START; // Loop again and start over&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Notes</id>
		<title>UI Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Notes"/>
				<updated>2015-07-03T12:26:33Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* user_data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
Here is some general information about getting information to display in a user interface:&lt;br /&gt;
&lt;br /&gt;
== UPnP messaging system  ==&lt;br /&gt;
&lt;br /&gt;
Vera uses UPnP for all the messaging, such as turning lights on and off.  So Vera translates Z-Wave, Insteon, infrared codes, etc., into UPnP actions. If you have already implemented a UPnP stack and can send properly formated UPnP SOAP/XML requests, you can control everything using standard UPnP action invocation. If you did not, Vera provides a simple HTTP GET interface as well, which is discussed below.&lt;br /&gt;
&lt;br /&gt;
In a nutshell UPnP works like this: You have UPnP devices, which are things that can be controlled and can report their state, like a light switch.  And you have UPnP Control Points, which are the things that let a user control UPnP devices, like a touch-screen web pad.  The Control Point does this by a) reading the device and descriptions for the UPnP device to see what it can do, and b) invoking actions on the UPnP device (ie telling it to do something), and c) reading and setting variables for the device which describe the current state and/or configuration settings for the device.&lt;br /&gt;
&lt;br /&gt;
A UPnP device is defined in an XML document called a device description document.  To see one, in Vera's setup UI, go to Devices, Luup plugins, Luup Files, and click 'view' file next to D_BinaryLight1.xml.  Use Firefox since it has a built-in XML viewer.  Notice the tag: &amp;lt;deviceType&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/deviceType&amp;gt;.  This defines the type of device, namely an on/off light switch, which is what you use to know how to represent this device to a user.  A device optionally implements one or more services.  In this case the services: urn:upnp-org:serviceId:SwitchPower1, urn:micasaverde-com:serviceId:EnergyMetering1 and urn:micasaverde-com:serviceId:HaDevice1.&lt;br /&gt;
&lt;br /&gt;
A service is a collection of actions which a device implement and which you can invoke from a UPnP Control Point, as well as a collection of variables which always have a current value.  The variables describe the current state of the device and/or configuration settings.  View the file S_SwitchPower1.xml to see a service.  For example, the device urn:schemas-upnp-org:device:BinaryLight:1 implements the service urn:upnp-org:serviceId:SwitchPower1, which has the action SetTarget, which is how you turn the light on and off.  The action takes a single argument newTargetValue which can be 0 to turn the light off and 1 to turn it on.  The service also has the variable Status which is 0 or 1 depending on whether the light is currently on or off.&lt;br /&gt;
&lt;br /&gt;
If you open the device description for a dimmable light D_DimmableLight1.xml you'll see that it implements the same service S_SwitchPower1.xml, since you can still turn it on and off, and it also implements the service urn:upnp-org:serviceId:Dimming1, which has an action to set the dim level (SetLoadLevelTarget).&lt;br /&gt;
&lt;br /&gt;
To test UPnP calls you can use the Intel Device Spy utility available [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology_v2.zip here].  It should pick up Vera, show you all the devices, like light switches, thermostats, etc., let you expand the services and see the actions and variables.  Click an action, like SetTarget, to specify the arguments and click 'Invoke' to run the action, such as turning on and off the light.&lt;br /&gt;
&lt;br /&gt;
== JSON vs. XML ==&lt;br /&gt;
&lt;br /&gt;
The native UPnP protocol uses XML/SOAP.  But there are also several times you will request data from Vera that has nothing to do with the UPnP spec.  These will be done with data_request's as explained below, such as user_data, lu_status, etc.  Internally Vera uses JSON as the native format, but Vera can convert to XML (details follow).  In general when you want to view data in a human readable format, such as the device list, it's easiest to use the Firefox browser, and request Vera convert the data to XML.  Firefox has a nice browser to display XML in human readable format.  If you want to make the JSON data nicely formatted, you can use the web site jsonlint.com.  In a UI application which will request data regularly from Vera we recommend retrieving everything in JSON format, not XML, because Vera's CPU is not that powerful and so continuous requests of data in XML format will cause a lot of CPU time to be devoted to converting JSON into XML.&lt;br /&gt;
&lt;br /&gt;
== Finding Vera on the local network  ==&lt;br /&gt;
&lt;br /&gt;
You can find Vera by using the traditional UPnP discovery process, or you can retrieve this URL:&amp;lt;br&amp;gt;'''https://sta1.mios.com/locator_json.php?username=xxx''' where the username=xxx is optional, but, if specified, it will report all systems that mios.com user xxx can report whether local or remote, and without the username=xxx it only shows the Vera's on the user's local home network.&lt;br /&gt;
&lt;br /&gt;
Each Vera, when it boots up, reports its internal IP address to the central mios.com server, which tracks this along with the external IP address. '''locator.php''' shows all serial numbers and internal network IP addresses on the same external IP. For example, if '''https://sta1.mios.com/locator_json.php?username=xxx'''.&lt;br /&gt;
&lt;br /&gt;
== The HTTP interface  ==&lt;br /&gt;
&lt;br /&gt;
Vera listens on port 3480. Vera responds to UPnP actions the normal way, or by making simple HTTP requests. For example, to turn on a light you can either send the UPnP action &amp;quot;SetTarget&amp;quot; to the device using the normal UPnP mechanism, or you can simply put this URL in your web browser, or with wget, or similar: &lt;br /&gt;
&lt;br /&gt;
http://[ipadress]:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
That URL will return the same results of the action as using the normal UPnP architecture. The '''output_format=xml''' on the URL means the data returned should be in XML format. You can instead use '''output_format=json'''&lt;br /&gt;
&lt;br /&gt;
The service ID's, actions, and arguments are all defined by the UPnP forum.  A list of ratified UPnP devices and services is available on the [http://www.upnp.org UPnP Forum].  Mi Casa Verde added its own custom devices and services when there was no existing UPnP standard.  A list of these can be found in the [[Luup_UPNP_Files]] header files.&lt;br /&gt;
&lt;br /&gt;
== Getting the system configuration  ==&lt;br /&gt;
&lt;br /&gt;
Either use the UPnP service/action:&amp;lt;br&amp;gt; '''urn:micasaverde-com:serviceId:HomeAutomationGateway1/GetUserData''' &lt;br /&gt;
&lt;br /&gt;
or use the built-in request: &lt;br /&gt;
&lt;br /&gt;
'''http://ipaddress:3480/data_request?id=user_data2&amp;amp;amp;output_format=json''' (or xml) &lt;br /&gt;
&lt;br /&gt;
This returns the system configuration file for Vera. It's assumed you understand the way Vera categorizes devices with Rooms, Devices, Scenes, etc. When creating a user interface for controlling Vera only, like on a mobile phone, most of the tags can be ignored, since usually you just need the list of rooms and devices.&lt;br /&gt;
&lt;br /&gt;
== Accessing Vera remotely through the mios server ==&lt;br /&gt;
&lt;br /&gt;
Native UPnP only works on a local area home network, and cannot be used over the Internet.  The mios server provides a secure way to remotely access and control your Vera system using the HTTP interface without having to make any substantial changes to the UI.  Everything you can do locally with Vera on port 3480, you can do remotely with mios using the exact same syntax.  You only need to ask the user for his username and password and pass them on the URL to the remote access server, along with the serial number of the unit (ie like 12345).  For example, the above user_data is the syntax for local access on a home network.  To retrieve the same URL over the internet with mios use:&lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/demovera/myvera123/12345/data_request?id=lu_status&amp;amp;output_format=json (or use fwd1.mios.com)&lt;br /&gt;
&lt;br /&gt;
assuming demovera is the username and myvera123 is the password that the user chose setting up his mios.com account.  Note that since the request is https, the username and password are encrypted because https encrypts the URL's as well as the contents of the page.&lt;br /&gt;
&lt;br /&gt;
== Building a control-only UI for Vera  ==&lt;br /&gt;
&lt;br /&gt;
If you just want to control Vera, and not modify the configuration, such as with a cell phone interface or web pad, the flow might possibly work like this: &lt;br /&gt;
&lt;br /&gt;
'''1)''' For the initial setup, you need to ask whether the user wants to (a)&amp;amp;nbsp;access Vera remotely with the mios service, and if so, get the user's username/password; or (b) access Vera directly on the home network. You can use locator.php to show the Vera on the home network. You might want to do an auto-detect. For example, you could use locator.php to see if Vera exists locally, and if not, prompt the user for a mios username and password. You can use locator.php and pass the username to get the serial number and internal IP, and then automatically switch to direct access if locator.php (without the username) indicates that serial number is found on the local network. This would allow the user to automatically switch between local access with Wi-Fi (which is much faster of course) and remote access with mios and the mobile phone network.  Or just ask for his mios username and show him all the Vera's he can control, either local or remote.&lt;br /&gt;
&lt;br /&gt;
'''2)''' Once the connection is established, retrieve the list of rooms, scenes, and devices from Vera (see '''user_data''' below). You can cache this data locally so you don't need to retrieve it and parse it over and over.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Present the user with the rooms, scenes, devices.  In Vera's UI's we show first the rooms and then let the user pick a device or scene in the room.  However this data could be presented graphically, such as on a floorplan.  Your UI can have Vera store extra tags and data in the configuration database (ie user_data) to store things like coordinates for icons, outlines or rooms and so on.&lt;br /&gt;
&lt;br /&gt;
'''4)''' If the user picks a scene you can run the scene with the following URL, passing the scene number as '''x''', and it will return an OK if it went okay: &lt;br /&gt;
&lt;br /&gt;
http://127.0.0.1:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=x &lt;br /&gt;
&lt;br /&gt;
'''5)''' If the user picks a device, you use the category which is contained in the user_data to determine what type of controls to present the user. (See [[Luup UPNP Files]] for a list of the categories.) When the user chooses an action, you can send it like this: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
For a list of common actions and device types see: [[Luup CP Mandatory Types]] &lt;br /&gt;
&lt;br /&gt;
Some actions return immediately with an 'OK'. Other jobs may take time to complete and are processed asynchronously.  For these asynchronous jobs you will get a job ID back.  There are several ways to present this to the user.  One possibility is to do what Vera does in the UI, namely to use '''lu_status '''(explained next) to find all active jobs and to put a 'job' icon next to each device to indicate the progress of the job. In this way the user isn't tracking a particular job ''per se'', but just has visual feedback that a device is busy, and if the job icon(s) turn green, that everything went through okay. You could instead track the action individually using the job number that is returned, or use some other method, like making the icon for the device appear animated while it's busy, and turn green or red if the last command succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
'''6)''' Periodically poll the system with '''lu_status''' (explained below), like this: &lt;br /&gt;
&lt;br /&gt;
http://ipaddress:3480/data_request?id=lu_status&amp;amp;amp;output_format=json &lt;br /&gt;
&lt;br /&gt;
That returns the current values of the UPnP variables, which you can use to show the user current status. For example, if the variable Status is 1 for a switch, you can show the 'on' button in a selected state, while 0 shows it in an 'off' state. '''lu_status''' also shows any active jobs for a device.&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
&lt;br /&gt;
The user_data is the main configuration file that Vera uses to store all the rooms, devices, scenes, timers, events, users, and any other data about the system.  You should request the user_data to get whatever data you need to present to the user, at a minimum, for example, you'll need the list of devices, their descriptions, and the categories (light switch, thermostat, etc.).  You'll also want the list of scenes to present the user.  To fetch the current user_data from Vera use the user_data request, like this:&lt;br /&gt;
&lt;br /&gt;
Returns JSON (preferred native format):&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&lt;br /&gt;
&lt;br /&gt;
Returns XML:&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
You can also add a 'DataVersion=TimeStamp' parameter to the URL. It the data has changed since the TimeStamp, all the data is returned. If the data has not changed since the TimeStamp, Vera will return a page with the text 'NO_CHANGES':&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
The user_data contains the state for all the devices.  For example this indicates that the device id #17, called &amp;quot;Switch&amp;quot; is turned off (ie service SwitchPower1, variable Status is 0)&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 17,&lt;br /&gt;
            &amp;quot;category&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;room&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Switch&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;mac&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: &amp;quot;0&amp;quot; &lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
     ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
{{Warning|On UI7 build lu_sdata and lu_status have been deprecated, and you should use &amp;quot;status&amp;quot; instead.}}&lt;br /&gt;
&lt;br /&gt;
==lu_status==&lt;br /&gt;
The UPnP variables describe the state of the devices according to the UPnP specs. When the variables change that information needs to be shown to the user, eg change a Switch icon from off to on. If you are interfacing with Vera using the UPnP stack, you can subscribe to the device's events to receive notifications automatically when a device's state changes. However if you're using the web interface you will need to poll using lu_status request.&lt;br /&gt;
&lt;br /&gt;
Call lu_status request like so:&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The returned document contains four sets of information, which constantly change to reflect the current status:&lt;br /&gt;
* root attributes including DataVersion, which is the status timestamp, plus other attributes such as LoadTime &lt;br /&gt;
*the state of the system initialization, such as initialization of the plugin modules.&lt;br /&gt;
*a '''subset''' of the user_data that represents the current state of the device's UPnP variables&lt;br /&gt;
*the status of any active or recent '''jobs''', such as if a light was successfully turned off&lt;br /&gt;
&lt;br /&gt;
===Tracking status changes===&lt;br /&gt;
If you call lu_status without passing a DataVersion on the URL, you will get the current value of all the UPnP variables for a device.  Note that most of the UPnP variables do not ever change.  For example, with a light switch, only the variable &amp;quot;SwitchPower:Status&amp;quot; changes, as the switch is turned off and on.  There are many other variables, like &amp;quot;Capabilities&amp;quot; which are simply configuration data or settings the user modified.  If you pass &amp;amp;DataVersion=1 on the URL, you will only see the UPnP variables which have changed since the Luup engine started.  So, if you parse the initial UPnP variables when you first call user_data, you can call lu_status with DataVersion=1.  Once you call lu_status the first time, store the DataVersion and on subsequent calls pass it on the URL and you will only get the UPnP variables which have changed since that last DataVersion.  Regardless, you will also get the current state of jobs and system initialization.&lt;br /&gt;
&lt;br /&gt;
On subsequent calls to lu_status, you should also pass back in the LoadTime which you received on the prior call.&lt;br /&gt;
&lt;br /&gt;
===Controlling the poll timing===&lt;br /&gt;
You can also pass in a Timeout value, which means the call will block for up to that many seconds if nothing has changed, and will return immediately when something does.  This way you can have infrequent polling, say every 60 seconds by putting a Timeout value of 60, but your UI will be immediately responsive since, when something changes, it returns immediately.  You can also add a MinimumDelay, which means that the call will wait for at least that many milliseconds.  This is advisable so that in the event there are lots of continuous changes, such as a scene turning off many lights, you won't have lu_status calls returning non-stop consuming all the resources on both the Vera and the UI.&lt;br /&gt;
&lt;br /&gt;
===Startup status===&lt;br /&gt;
The section with the initialization tasks is shown in the startup tag as shown:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;startup&amp;quot;: {&lt;br /&gt;
        &amp;quot;tasks&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: 0,&lt;br /&gt;
                &amp;quot;status&amp;quot;: 2,&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;ZWave&amp;quot;,&lt;br /&gt;
                &amp;quot;comments&amp;quot;: &amp;quot;No Z-Wave&amp;quot; &lt;br /&gt;
            },&lt;br /&gt;
&lt;br /&gt;
The startup tasks begin whenever the Luup engine is reset, such as after the user makes a configuration change.  Ever plugin and module in the Luup engine does a startup sequence.  The id is not really important.  The status numbers are the same as for jobs, so 2 means the module failed to startup.  The 'Type' is what you can use to key off of to know which module is being reported, such as &amp;quot;ZWave&amp;quot;, and comments are just notes indicating the current state.  For example, &amp;quot;No Z-Wave&amp;quot; means there's no Z-Wave dongle connected.&lt;br /&gt;
&lt;br /&gt;
Once all the plugins have been initialized successfully the startup section will disappear completely from lu_status.&lt;br /&gt;
&lt;br /&gt;
Note that lu_status also returns UserData_DataVersion, which is the dataversion from user_data.  That way you don't need to poll user_data in parallel.  Simply retrieve the user_data one time at startup, then poll lu_status, and, if UserData_DataVersion is different from the previous user_data you retrieved, then download user_data again.&lt;br /&gt;
&lt;br /&gt;
Some notes on building a full replacement, including configuration, are available here [[UI_Notes_Replacement]], however the syntax is not up to date with the Luup architecture.&lt;br /&gt;
&lt;br /&gt;
===Job status===&lt;br /&gt;
The jobs for a device will look like this:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;Jobs&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;name&amp;quot;: &amp;quot;job#1 :getnodes (0x00D068F0) P:10 S:4&amp;quot;,&lt;br /&gt;
                    &amp;quot;icon&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;4&amp;quot; &lt;br /&gt;
                } &lt;br /&gt;
            ] &lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
The id is the job id number.  When you run an action, like turning on a light, if it happens asynchronously, you'll get a job id number.  All pending jobs for a device are shown by their id number.  The name is just an internal name for the job.  Icon is an optional keyword to indicate what sort of icon should be shown to the user.  For example, 'getnodes' has no icon, meaning this type of job is generally not of interest to a user.  If the icon was 'ON' or 'OFF' that would mean this job is busy turning on or off a light.  Comments is notes about the job, if any.  This may be shown to a user in a tool tip or similar, but is generally more technical than users would care to know.  The status indicates the current state of the job, as shown:&lt;br /&gt;
&lt;br /&gt;
*job_None=-1,  // no icon&lt;br /&gt;
*job_WaitingToStart=0,  // gray icon&lt;br /&gt;
*job_InProgress=1,  // blue icon&lt;br /&gt;
*job_Error=2,  // red icon&lt;br /&gt;
*job_Aborted=3,  // red icon&lt;br /&gt;
*job_Done=4,  // green icon&lt;br /&gt;
*job_WaitingForCallback=5  // blue icon - Special case used in certain derived classes&lt;br /&gt;
&lt;br /&gt;
If the status is 0, this means the job is queued but hasn't started.  If it's 1 or 5 the job is being executed right now.  Generally both 1 and 5 are presented to the user the same way as a 'busy', although technically 1 means Vera is actively talking to the device, and 5 means Vera is waiting for a reply from the device.  Status codes 2, 3 and 4 mean the job has finished.  4 means the job went ok, and both 2 and 3 mean it failed.  Technically 3 means the job was aborted by another job or an external process, like a user cancelling it, while 2 means it failed due to a problem talking to the device.  In both cases this is usually presented the user the same way, as a failure.&lt;br /&gt;
&lt;br /&gt;
== Categories and device types ==&lt;br /&gt;
&lt;br /&gt;
The values used in user_data to determine the types of devices are in [[Luup_UPNP_Files]].  In general you can use the category instead of the devicetype since it's an integer and is thus faster to compare:&lt;br /&gt;
&lt;br /&gt;
== pseudo-code for a UI ==&lt;br /&gt;
&lt;br /&gt;
Here is some pseudo code to show how the polling mechanism should be properly implemented.  The parsing code is, of course, unique to your UI, so placeholder function names are shown here, like FetchAndParse.  This shows the flow for handling the polling so you know you get the changes reported correctly.&lt;br /&gt;
&lt;br /&gt;
 variable int DataVersion_lustatus=0&lt;br /&gt;
 variable int LoadTime=0&lt;br /&gt;
 variable int DataVersion_userdata=0&lt;br /&gt;
&lt;br /&gt;
:START&lt;br /&gt;
  variable boolean FetchUserData=false;&lt;br /&gt;
  if( DataVersion_userdata==0 )  // If we're on the first loop and haven't retrieved user_data, do it and don't do an lu_status&lt;br /&gt;
    FetchUserData=true;&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
     while(true)&lt;br /&gt;
     {&lt;br /&gt;
         newdata = FetchAndParse(&amp;quot;lu_status&amp;amp;DataVersion=&amp;quot;+DataVersion_lustatus+&amp;quot;&amp;amp;LoadTime=&amp;quot;+LoadTime);&lt;br /&gt;
         if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
            break;  // If we got data, continue on and process it&lt;br /&gt;
        else&lt;br /&gt;
            Sleep 1; // If we didn't get anything, or if lu_status failed, just sleep 1 second and stay in the loop to try again&lt;br /&gt;
     } // End of while loop&lt;br /&gt;
&lt;br /&gt;
     if( newdata.UserData_DataVersion!=DataVersion_userdata )&lt;br /&gt;
     {&lt;br /&gt;
        FetchUserData=true;&lt;br /&gt;
     }&lt;br /&gt;
     else  // Only Parse if userdata is the same, otherwise we're going to reload user_data&lt;br /&gt;
     {&lt;br /&gt;
        ParseLuStatus();  // This won't run if user_data has changed&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
      }&lt;br /&gt;
  }  // end of else loop&lt;br /&gt;
&lt;br /&gt;
 if( FetchUserData==true )&lt;br /&gt;
{&lt;br /&gt;
   UI.HourglassAndSuspend(true); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
   newdata = FetchAndParse(&amp;quot;user_data2&amp;quot;);&lt;br /&gt;
    if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
    {&lt;br /&gt;
        ParseUserData();&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
         LoadTime=newdata.LoadTime&lt;br /&gt;
         DataVersion_userdata=newdata.DataVersion&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
       UI.DisplayError(&amp;quot;Failed to update data&amp;quot;); // Display in the info panel an error message that the user will see for 10 seconds or so&lt;br /&gt;
&lt;br /&gt;
   UI.HourglassAndSuspend(false); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Sleep 1; // We know we just parsed user_data or lu_status, so sleep before looping&lt;br /&gt;
goto START; // Loop again and start over&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Notes</id>
		<title>UI Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Notes"/>
				<updated>2015-06-04T12:07:37Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
Here is some general information about getting information to display in a user interface:&lt;br /&gt;
&lt;br /&gt;
== UPnP messaging system  ==&lt;br /&gt;
&lt;br /&gt;
Vera uses UPnP for all the messaging, such as turning lights on and off.  So Vera translates Z-Wave, Insteon, infrared codes, etc., into UPnP actions. If you have already implemented a UPnP stack and can send properly formated UPnP SOAP/XML requests, you can control everything using standard UPnP action invocation. If you did not, Vera provides a simple HTTP GET interface as well, which is discussed below.&lt;br /&gt;
&lt;br /&gt;
In a nutshell UPnP works like this: You have UPnP devices, which are things that can be controlled and can report their state, like a light switch.  And you have UPnP Control Points, which are the things that let a user control UPnP devices, like a touch-screen web pad.  The Control Point does this by a) reading the device and descriptions for the UPnP device to see what it can do, and b) invoking actions on the UPnP device (ie telling it to do something), and c) reading and setting variables for the device which describe the current state and/or configuration settings for the device.&lt;br /&gt;
&lt;br /&gt;
A UPnP device is defined in an XML document called a device description document.  To see one, in Vera's setup UI, go to Devices, Luup plugins, Luup Files, and click 'view' file next to D_BinaryLight1.xml.  Use Firefox since it has a built-in XML viewer.  Notice the tag: &amp;lt;deviceType&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/deviceType&amp;gt;.  This defines the type of device, namely an on/off light switch, which is what you use to know how to represent this device to a user.  A device optionally implements one or more services.  In this case the services: urn:upnp-org:serviceId:SwitchPower1, urn:micasaverde-com:serviceId:EnergyMetering1 and urn:micasaverde-com:serviceId:HaDevice1.&lt;br /&gt;
&lt;br /&gt;
A service is a collection of actions which a device implement and which you can invoke from a UPnP Control Point, as well as a collection of variables which always have a current value.  The variables describe the current state of the device and/or configuration settings.  View the file S_SwitchPower1.xml to see a service.  For example, the device urn:schemas-upnp-org:device:BinaryLight:1 implements the service urn:upnp-org:serviceId:SwitchPower1, which has the action SetTarget, which is how you turn the light on and off.  The action takes a single argument newTargetValue which can be 0 to turn the light off and 1 to turn it on.  The service also has the variable Status which is 0 or 1 depending on whether the light is currently on or off.&lt;br /&gt;
&lt;br /&gt;
If you open the device description for a dimmable light D_DimmableLight1.xml you'll see that it implements the same service S_SwitchPower1.xml, since you can still turn it on and off, and it also implements the service urn:upnp-org:serviceId:Dimming1, which has an action to set the dim level (SetLoadLevelTarget).&lt;br /&gt;
&lt;br /&gt;
To test UPnP calls you can use the Intel Device Spy utility available [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology_v2.zip here].  It should pick up Vera, show you all the devices, like light switches, thermostats, etc., let you expand the services and see the actions and variables.  Click an action, like SetTarget, to specify the arguments and click 'Invoke' to run the action, such as turning on and off the light.&lt;br /&gt;
&lt;br /&gt;
== JSON vs. XML ==&lt;br /&gt;
&lt;br /&gt;
The native UPnP protocol uses XML/SOAP.  But there are also several times you will request data from Vera that has nothing to do with the UPnP spec.  These will be done with data_request's as explained below, such as user_data, lu_status, etc.  Internally Vera uses JSON as the native format, but Vera can convert to XML (details follow).  In general when you want to view data in a human readable format, such as the device list, it's easiest to use the Firefox browser, and request Vera convert the data to XML.  Firefox has a nice browser to display XML in human readable format.  If you want to make the JSON data nicely formatted, you can use the web site jsonlint.com.  In a UI application which will request data regularly from Vera we recommend retrieving everything in JSON format, not XML, because Vera's CPU is not that powerful and so continuous requests of data in XML format will cause a lot of CPU time to be devoted to converting JSON into XML.&lt;br /&gt;
&lt;br /&gt;
== Finding Vera on the local network  ==&lt;br /&gt;
&lt;br /&gt;
You can find Vera by using the traditional UPnP discovery process, or you can retrieve this URL:&amp;lt;br&amp;gt;'''https://sta1.mios.com/locator_json.php?username=xxx''' where the username=xxx is optional, but, if specified, it will report all systems that mios.com user xxx can report whether local or remote, and without the username=xxx it only shows the Vera's on the user's local home network.&lt;br /&gt;
&lt;br /&gt;
Each Vera, when it boots up, reports its internal IP address to the central mios.com server, which tracks this along with the external IP address. '''locator.php''' shows all serial numbers and internal network IP addresses on the same external IP. For example, if '''https://sta1.mios.com/locator_json.php?username=xxx'''.&lt;br /&gt;
&lt;br /&gt;
== The HTTP interface  ==&lt;br /&gt;
&lt;br /&gt;
Vera listens on port 3480. Vera responds to UPnP actions the normal way, or by making simple HTTP requests. For example, to turn on a light you can either send the UPnP action &amp;quot;SetTarget&amp;quot; to the device using the normal UPnP mechanism, or you can simply put this URL in your web browser, or with wget, or similar: &lt;br /&gt;
&lt;br /&gt;
http://[ipadress]:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
That URL will return the same results of the action as using the normal UPnP architecture. The '''output_format=xml''' on the URL means the data returned should be in XML format. You can instead use '''output_format=json'''&lt;br /&gt;
&lt;br /&gt;
The service ID's, actions, and arguments are all defined by the UPnP forum.  A list of ratified UPnP devices and services is available on the [http://www.upnp.org UPnP Forum].  Mi Casa Verde added its own custom devices and services when there was no existing UPnP standard.  A list of these can be found in the [[Luup_UPNP_Files]] header files.&lt;br /&gt;
&lt;br /&gt;
== Getting the system configuration  ==&lt;br /&gt;
&lt;br /&gt;
Either use the UPnP service/action:&amp;lt;br&amp;gt; '''urn:micasaverde-com:serviceId:HomeAutomationGateway1/GetUserData''' &lt;br /&gt;
&lt;br /&gt;
or use the built-in request: &lt;br /&gt;
&lt;br /&gt;
'''http://ipaddress:3480/data_request?id=user_data2&amp;amp;amp;output_format=json''' (or xml) &lt;br /&gt;
&lt;br /&gt;
This returns the system configuration file for Vera. It's assumed you understand the way Vera categorizes devices with Rooms, Devices, Scenes, etc. When creating a user interface for controlling Vera only, like on a mobile phone, most of the tags can be ignored, since usually you just need the list of rooms and devices.&lt;br /&gt;
&lt;br /&gt;
== Accessing Vera remotely through the mios server ==&lt;br /&gt;
&lt;br /&gt;
Native UPnP only works on a local area home network, and cannot be used over the Internet.  The mios server provides a secure way to remotely access and control your Vera system using the HTTP interface without having to make any substantial changes to the UI.  Everything you can do locally with Vera on port 3480, you can do remotely with mios using the exact same syntax.  You only need to ask the user for his username and password and pass them on the URL to the remote access server, along with the serial number of the unit (ie like 12345).  For example, the above user_data is the syntax for local access on a home network.  To retrieve the same URL over the internet with mios use:&lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/demovera/myvera123/12345/data_request?id=lu_status&amp;amp;output_format=json (or use fwd1.mios.com)&lt;br /&gt;
&lt;br /&gt;
assuming demovera is the username and myvera123 is the password that the user chose setting up his mios.com account.  Note that since the request is https, the username and password are encrypted because https encrypts the URL's as well as the contents of the page.&lt;br /&gt;
&lt;br /&gt;
== Building a control-only UI for Vera  ==&lt;br /&gt;
&lt;br /&gt;
If you just want to control Vera, and not modify the configuration, such as with a cell phone interface or web pad, the flow might possibly work like this: &lt;br /&gt;
&lt;br /&gt;
'''1)''' For the initial setup, you need to ask whether the user wants to (a)&amp;amp;nbsp;access Vera remotely with the mios service, and if so, get the user's username/password; or (b) access Vera directly on the home network. You can use locator.php to show the Vera on the home network. You might want to do an auto-detect. For example, you could use locator.php to see if Vera exists locally, and if not, prompt the user for a mios username and password. You can use locator.php and pass the username to get the serial number and internal IP, and then automatically switch to direct access if locator.php (without the username) indicates that serial number is found on the local network. This would allow the user to automatically switch between local access with Wi-Fi (which is much faster of course) and remote access with mios and the mobile phone network.  Or just ask for his mios username and show him all the Vera's he can control, either local or remote.&lt;br /&gt;
&lt;br /&gt;
'''2)''' Once the connection is established, retrieve the list of rooms, scenes, and devices from Vera (see '''user_data''' below). You can cache this data locally so you don't need to retrieve it and parse it over and over.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Present the user with the rooms, scenes, devices.  In Vera's UI's we show first the rooms and then let the user pick a device or scene in the room.  However this data could be presented graphically, such as on a floorplan.  Your UI can have Vera store extra tags and data in the configuration database (ie user_data) to store things like coordinates for icons, outlines or rooms and so on.&lt;br /&gt;
&lt;br /&gt;
'''4)''' If the user picks a scene you can run the scene with the following URL, passing the scene number as '''x''', and it will return an OK if it went okay: &lt;br /&gt;
&lt;br /&gt;
http://127.0.0.1:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=x &lt;br /&gt;
&lt;br /&gt;
'''5)''' If the user picks a device, you use the category which is contained in the user_data to determine what type of controls to present the user. (See [[Luup UPNP Files]] for a list of the categories.) When the user chooses an action, you can send it like this: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
For a list of common actions and device types see: [[Luup CP Mandatory Types]] &lt;br /&gt;
&lt;br /&gt;
Some actions return immediately with an 'OK'. Other jobs may take time to complete and are processed asynchronously.  For these asynchronous jobs you will get a job ID back.  There are several ways to present this to the user.  One possibility is to do what Vera does in the UI, namely to use '''lu_status '''(explained next) to find all active jobs and to put a 'job' icon next to each device to indicate the progress of the job. In this way the user isn't tracking a particular job ''per se'', but just has visual feedback that a device is busy, and if the job icon(s) turn green, that everything went through okay. You could instead track the action individually using the job number that is returned, or use some other method, like making the icon for the device appear animated while it's busy, and turn green or red if the last command succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
'''6)''' Periodically poll the system with '''lu_status''' (explained below), like this: &lt;br /&gt;
&lt;br /&gt;
http://ipaddress:3480/data_request?id=lu_status&amp;amp;amp;output_format=json &lt;br /&gt;
&lt;br /&gt;
That returns the current values of the UPnP variables, which you can use to show the user current status. For example, if the variable Status is 1 for a switch, you can show the 'on' button in a selected state, while 0 shows it in an 'off' state. '''lu_status''' also shows any active jobs for a device.&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
NOTE: On UI3 builds, user_data2 and user_data are the same, and so is lu_status and lu_status. However, on UI2 builds, user_data and lu_status have been deprecated, and you should user_data2 and lu_status. Therefore, it's best to simply always use user_data2 instead of user_data, and lu_status instead of lu_status.&lt;br /&gt;
&lt;br /&gt;
The user_data is the main configuration file that Vera uses to store all the rooms, devices, scenes, timers, events, users, and any other data about the system.  You should request the user_data to get whatever data you need to present to the user, at a minimum, for example, you'll need the list of devices, their descriptions, and the categories (light switch, thermostat, etc.).  You'll also want the list of scenes to present the user.  To fetch the current user_data from Vera use the user_data2 request, like this:&lt;br /&gt;
&lt;br /&gt;
Returns JSON (preferred native format):&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&lt;br /&gt;
&lt;br /&gt;
Returns XML:&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
You can also add a 'DataVersion=TimeStamp' parameter to the URL. It the data has changed since the TimeStamp, all the data is returned. If the data has not changed since the TimeStamp, Vera will return a page with the text 'NO_CHANGES':&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
The user_data contains the state for all the devices.  For example this indicates that the device id #17, called &amp;quot;Switch&amp;quot; is turned off (ie service SwitchPower1, variable Status is 0)&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 17,&lt;br /&gt;
            &amp;quot;category&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;room&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Switch&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;mac&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: &amp;quot;0&amp;quot; &lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
     ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
==lu_status==&lt;br /&gt;
The UPnP variables describe the state of the devices according to the UPnP specs. When the variables change that information needs to be shown to the user, eg change a Switch icon from off to on. If you are interfacing with Vera using the UPnP stack, you can subscribe to the device's events to receive notifications automatically when a device's state changes. However if you're using the web interface you will need to poll using lu_status request.&lt;br /&gt;
&lt;br /&gt;
Call lu_status request like so:&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The returned document contains four sets of information, which constantly change to reflect the current status:&lt;br /&gt;
* root attributes including DataVersion, which is the status timestamp, plus other attributes such as LoadTime &lt;br /&gt;
*the state of the system initialization, such as initialization of the plugin modules.&lt;br /&gt;
*a '''subset''' of the user_data that represents the current state of the device's UPnP variables&lt;br /&gt;
*the status of any active or recent '''jobs''', such as if a light was successfully turned off&lt;br /&gt;
&lt;br /&gt;
===Tracking status changes===&lt;br /&gt;
If you call lu_status without passing a DataVersion on the URL, you will get the current value of all the UPnP variables for a device.  Note that most of the UPnP variables do not ever change.  For example, with a light switch, only the variable &amp;quot;SwitchPower:Status&amp;quot; changes, as the switch is turned off and on.  There are many other variables, like &amp;quot;Capabilities&amp;quot; which are simply configuration data or settings the user modified.  If you pass &amp;amp;DataVersion=1 on the URL, you will only see the UPnP variables which have changed since the Luup engine started.  So, if you parse the initial UPnP variables when you first call user_data, you can call lu_status with DataVersion=1.  Once you call lu_status the first time, store the DataVersion and on subsequent calls pass it on the URL and you will only get the UPnP variables which have changed since that last DataVersion.  Regardless, you will also get the current state of jobs and system initialization.&lt;br /&gt;
&lt;br /&gt;
On subsequent calls to lu_status, you should also pass back in the LoadTime which you received on the prior call.&lt;br /&gt;
&lt;br /&gt;
===Controlling the poll timing===&lt;br /&gt;
You can also pass in a Timeout value, which means the call will block for up to that many seconds if nothing has changed, and will return immediately when something does.  This way you can have infrequent polling, say every 60 seconds by putting a Timeout value of 60, but your UI will be immediately responsive since, when something changes, it returns immediately.  You can also add a MinimumDelay, which means that the call will wait for at least that many milliseconds.  This is advisable so that in the event there are lots of continuous changes, such as a scene turning off many lights, you won't have lu_status calls returning non-stop consuming all the resources on both the Vera and the UI.&lt;br /&gt;
&lt;br /&gt;
===Startup status===&lt;br /&gt;
The section with the initialization tasks is shown in the startup tag as shown:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;startup&amp;quot;: {&lt;br /&gt;
        &amp;quot;tasks&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: 0,&lt;br /&gt;
                &amp;quot;status&amp;quot;: 2,&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;ZWave&amp;quot;,&lt;br /&gt;
                &amp;quot;comments&amp;quot;: &amp;quot;No Z-Wave&amp;quot; &lt;br /&gt;
            },&lt;br /&gt;
&lt;br /&gt;
The startup tasks begin whenever the Luup engine is reset, such as after the user makes a configuration change.  Ever plugin and module in the Luup engine does a startup sequence.  The id is not really important.  The status numbers are the same as for jobs, so 2 means the module failed to startup.  The 'Type' is what you can use to key off of to know which module is being reported, such as &amp;quot;ZWave&amp;quot;, and comments are just notes indicating the current state.  For example, &amp;quot;No Z-Wave&amp;quot; means there's no Z-Wave dongle connected.&lt;br /&gt;
&lt;br /&gt;
Once all the plugins have been initialized successfully the startup section will disappear completely from lu_status.&lt;br /&gt;
&lt;br /&gt;
Note that lu_status also returns UserData_DataVersion, which is the dataversion from user_data.  That way you don't need to poll user_data in parallel.  Simply retrieve the user_data one time at startup, then poll lu_status, and, if UserData_DataVersion is different from the previous user_data you retrieved, then download user_data again.&lt;br /&gt;
&lt;br /&gt;
Some notes on building a full replacement, including configuration, are available here [[UI_Notes_Replacement]], however the syntax is not up to date with the Luup architecture.&lt;br /&gt;
&lt;br /&gt;
===Job status===&lt;br /&gt;
The jobs for a device will look like this:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;Jobs&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;name&amp;quot;: &amp;quot;job#1 :getnodes (0x00D068F0) P:10 S:4&amp;quot;,&lt;br /&gt;
                    &amp;quot;icon&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;4&amp;quot; &lt;br /&gt;
                } &lt;br /&gt;
            ] &lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
The id is the job id number.  When you run an action, like turning on a light, if it happens asynchronously, you'll get a job id number.  All pending jobs for a device are shown by their id number.  The name is just an internal name for the job.  Icon is an optional keyword to indicate what sort of icon should be shown to the user.  For example, 'getnodes' has no icon, meaning this type of job is generally not of interest to a user.  If the icon was 'ON' or 'OFF' that would mean this job is busy turning on or off a light.  Comments is notes about the job, if any.  This may be shown to a user in a tool tip or similar, but is generally more technical than users would care to know.  The status indicates the current state of the job, as shown:&lt;br /&gt;
&lt;br /&gt;
*job_None=-1,  // no icon&lt;br /&gt;
*job_WaitingToStart=0,  // gray icon&lt;br /&gt;
*job_InProgress=1,  // blue icon&lt;br /&gt;
*job_Error=2,  // red icon&lt;br /&gt;
*job_Aborted=3,  // red icon&lt;br /&gt;
*job_Done=4,  // green icon&lt;br /&gt;
*job_WaitingForCallback=5  // blue icon - Special case used in certain derived classes&lt;br /&gt;
&lt;br /&gt;
If the status is 0, this means the job is queued but hasn't started.  If it's 1 or 5 the job is being executed right now.  Generally both 1 and 5 are presented to the user the same way as a 'busy', although technically 1 means Vera is actively talking to the device, and 5 means Vera is waiting for a reply from the device.  Status codes 2, 3 and 4 mean the job has finished.  4 means the job went ok, and both 2 and 3 mean it failed.  Technically 3 means the job was aborted by another job or an external process, like a user cancelling it, while 2 means it failed due to a problem talking to the device.  In both cases this is usually presented the user the same way, as a failure.&lt;br /&gt;
&lt;br /&gt;
== Categories and device types ==&lt;br /&gt;
&lt;br /&gt;
The values used in user_data to determine the types of devices are in [[Luup_UPNP_Files]].  In general you can use the category instead of the devicetype since it's an integer and is thus faster to compare:&lt;br /&gt;
&lt;br /&gt;
== pseudo-code for a UI ==&lt;br /&gt;
&lt;br /&gt;
Here is some pseudo code to show how the polling mechanism should be properly implemented.  The parsing code is, of course, unique to your UI, so placeholder function names are shown here, like FetchAndParse.  This shows the flow for handling the polling so you know you get the changes reported correctly.&lt;br /&gt;
&lt;br /&gt;
 variable int DataVersion_lustatus=0&lt;br /&gt;
 variable int LoadTime=0&lt;br /&gt;
 variable int DataVersion_userdata=0&lt;br /&gt;
&lt;br /&gt;
:START&lt;br /&gt;
  variable boolean FetchUserData=false;&lt;br /&gt;
  if( DataVersion_userdata==0 )  // If we're on the first loop and haven't retrieved user_data, do it and don't do an lu_status&lt;br /&gt;
    FetchUserData=true;&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
     while(true)&lt;br /&gt;
     {&lt;br /&gt;
         newdata = FetchAndParse(&amp;quot;lu_status&amp;amp;DataVersion=&amp;quot;+DataVersion_lustatus+&amp;quot;&amp;amp;LoadTime=&amp;quot;+LoadTime);&lt;br /&gt;
         if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
            break;  // If we got data, continue on and process it&lt;br /&gt;
        else&lt;br /&gt;
            Sleep 1; // If we didn't get anything, or if lu_status failed, just sleep 1 second and stay in the loop to try again&lt;br /&gt;
     } // End of while loop&lt;br /&gt;
&lt;br /&gt;
     if( newdata.UserData_DataVersion!=DataVersion_userdata )&lt;br /&gt;
     {&lt;br /&gt;
        FetchUserData=true;&lt;br /&gt;
     }&lt;br /&gt;
     else  // Only Parse if userdata is the same, otherwise we're going to reload user_data&lt;br /&gt;
     {&lt;br /&gt;
        ParseLuStatus();  // This won't run if user_data has changed&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
      }&lt;br /&gt;
  }  // end of else loop&lt;br /&gt;
&lt;br /&gt;
 if( FetchUserData==true )&lt;br /&gt;
{&lt;br /&gt;
   UI.HourglassAndSuspend(true); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
   newdata = FetchAndParse(&amp;quot;user_data2&amp;quot;);&lt;br /&gt;
    if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
    {&lt;br /&gt;
        ParseUserData();&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
         LoadTime=newdata.LoadTime&lt;br /&gt;
         DataVersion_userdata=newdata.DataVersion&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
       UI.DisplayError(&amp;quot;Failed to update data&amp;quot;); // Display in the info panel an error message that the user will see for 10 seconds or so&lt;br /&gt;
&lt;br /&gt;
   UI.HourglassAndSuspend(false); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Sleep 1; // We know we just parsed user_data or lu_status, so sleep before looping&lt;br /&gt;
goto START; // Loop again and start over&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Notes</id>
		<title>UI Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Notes"/>
				<updated>2015-06-04T12:06:17Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* lu_status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
Here is some general information about getting information to display in a user interface:&lt;br /&gt;
&lt;br /&gt;
== UPnP messaging system  ==&lt;br /&gt;
&lt;br /&gt;
Vera uses UPnP for all the messaging, such as turning lights on and off.  So Vera translates Z-Wave, Insteon, infrared codes, etc., into UPnP actions. If you have already implemented a UPnP stack and can send properly formated UPnP SOAP/XML requests, you can control everything using standard UPnP action invocation. If you did not, Vera provides a simple HTTP GET interface as well, which is discussed below.&lt;br /&gt;
&lt;br /&gt;
In a nutshell UPnP works like this: You have UPnP devices, which are things that can be controlled and can report their state, like a light switch.  And you have UPnP Control Points, which are the things that let a user control UPnP devices, like a touch-screen web pad.  The Control Point does this by a) reading the device and descriptions for the UPnP device to see what it can do, and b) invoking actions on the UPnP device (ie telling it to do something), and c) reading and setting variables for the device which describe the current state and/or configuration settings for the device.&lt;br /&gt;
&lt;br /&gt;
A UPnP device is defined in an XML document called a device description document.  To see one, in Vera's setup UI, go to Devices, Luup plugins, Luup Files, and click 'view' file next to D_BinaryLight1.xml.  Use Firefox since it has a built-in XML viewer.  Notice the tag: &amp;lt;deviceType&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/deviceType&amp;gt;.  This defines the type of device, namely an on/off light switch, which is what you use to know how to represent this device to a user.  A device optionally implements one or more services.  In this case the services: urn:upnp-org:serviceId:SwitchPower1, urn:micasaverde-com:serviceId:EnergyMetering1 and urn:micasaverde-com:serviceId:HaDevice1.&lt;br /&gt;
&lt;br /&gt;
A service is a collection of actions which a device implement and which you can invoke from a UPnP Control Point, as well as a collection of variables which always have a current value.  The variables describe the current state of the device and/or configuration settings.  View the file S_SwitchPower1.xml to see a service.  For example, the device urn:schemas-upnp-org:device:BinaryLight:1 implements the service urn:upnp-org:serviceId:SwitchPower1, which has the action SetTarget, which is how you turn the light on and off.  The action takes a single argument newTargetValue which can be 0 to turn the light off and 1 to turn it on.  The service also has the variable Status which is 0 or 1 depending on whether the light is currently on or off.&lt;br /&gt;
&lt;br /&gt;
If you open the device description for a dimmable light D_DimmableLight1.xml you'll see that it implements the same service S_SwitchPower1.xml, since you can still turn it on and off, and it also implements the service urn:upnp-org:serviceId:Dimming1, which has an action to set the dim level (SetLoadLevelTarget).&lt;br /&gt;
&lt;br /&gt;
To test UPnP calls you can use the Intel Device Spy utility available [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology_v2.zip here].  It should pick up Vera, show you all the devices, like light switches, thermostats, etc., let you expand the services and see the actions and variables.  Click an action, like SetTarget, to specify the arguments and click 'Invoke' to run the action, such as turning on and off the light.&lt;br /&gt;
&lt;br /&gt;
== JSON vs. XML ==&lt;br /&gt;
&lt;br /&gt;
The native UPnP protocol uses XML/SOAP.  But there are also several times you will request data from Vera that has nothing to do with the UPnP spec.  These will be done with data_request's as explained below, such as user_data, lu_status, etc.  Internally Vera uses JSON as the native format, but Vera can convert to XML (details follow).  In general when you want to view data in a human readable format, such as the device list, it's easiest to use the Firefox browser, and request Vera convert the data to XML.  Firefox has a nice browser to display XML in human readable format.  If you want to make the JSON data nicely formatted, you can use the web site jsonlint.com.  In a UI application which will request data regularly from Vera we recommend retrieving everything in JSON format, not XML, because Vera's CPU is not that powerful and so continuous requests of data in XML format will cause a lot of CPU time to be devoted to converting JSON into XML.&lt;br /&gt;
&lt;br /&gt;
== Finding Vera on the local network  ==&lt;br /&gt;
&lt;br /&gt;
You can find Vera by using the traditional UPnP discovery process, or you can retrieve this URL:&amp;lt;br&amp;gt;'''https://sta1.mios.com/locator_json.php?username=xxx''' where the username=xxx is optional, but, if specified, it will report all systems that mios.com user xxx can report whether local or remote, and without the username=xxx it only shows the Vera's on the user's local home network.&lt;br /&gt;
&lt;br /&gt;
Each Vera, when it boots up, reports its internal IP address to the central mios.com server, which tracks this along with the external IP address. '''locator.php''' shows all serial numbers and internal network IP addresses on the same external IP. For example, if '''https://sta1.mios.com/locator_json.php?username=xxx'''.&lt;br /&gt;
&lt;br /&gt;
== The HTTP interface  ==&lt;br /&gt;
&lt;br /&gt;
Vera listens on port 3480. Vera responds to UPnP actions the normal way, or by making simple HTTP requests. For example, to turn on a light you can either send the UPnP action &amp;quot;SetTarget&amp;quot; to the device using the normal UPnP mechanism, or you can simply put this URL in your web browser, or with wget, or similar: &lt;br /&gt;
&lt;br /&gt;
http://[ipadress]:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
That URL will return the same results of the action as using the normal UPnP architecture. The '''output_format=xml''' on the URL means the data returned should be in XML format. You can instead use '''output_format=json'''&lt;br /&gt;
&lt;br /&gt;
The service ID's, actions, and arguments are all defined by the UPnP forum.  A list of ratified UPnP devices and services is available on the [http://www.upnp.org UPnP Forum].  Mi Casa Verde added its own custom devices and services when there was no existing UPnP standard.  A list of these can be found in the [[Luup_UPNP_Files]] header files.&lt;br /&gt;
&lt;br /&gt;
== Getting the system configuration  ==&lt;br /&gt;
&lt;br /&gt;
Either use the UPnP service/action:&amp;lt;br&amp;gt; '''urn:micasaverde-com:serviceId:HomeAutomationGateway1/GetUserData''' &lt;br /&gt;
&lt;br /&gt;
or use the built-in request: &lt;br /&gt;
&lt;br /&gt;
'''http://ipaddress:3480/data_request?id=user_data2&amp;amp;amp;output_format=json''' (or xml) &lt;br /&gt;
&lt;br /&gt;
This returns the system configuration file for Vera. It's assumed you understand the way Vera categorizes devices with Rooms, Devices, Scenes, etc. When creating a user interface for controlling Vera only, like on a mobile phone, most of the tags can be ignored, since usually you just need the list of rooms and devices.&lt;br /&gt;
&lt;br /&gt;
== Accessing Vera remotely through the mios server ==&lt;br /&gt;
&lt;br /&gt;
Native UPnP only works on a local area home network, and cannot be used over the Internet.  The mios server provides a secure way to remotely access and control your Vera system using the HTTP interface without having to make any substantial changes to the UI.  Everything you can do locally with Vera on port 3480, you can do remotely with mios using the exact same syntax.  You only need to ask the user for his username and password and pass them on the URL to the remote access server, along with the serial number of the unit (ie like 12345).  For example, the above user_data is the syntax for local access on a home network.  To retrieve the same URL over the internet with mios use:&lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/demovera/myvera123/12345/data_request?id=lu_status&amp;amp;output_format=json (or use fwd1.mios.com)&lt;br /&gt;
&lt;br /&gt;
assuming demovera is the username and myvera123 is the password that the user chose setting up his mios.com account.  Note that since the request is https, the username and password are encrypted because https encrypts the URL's as well as the contents of the page.&lt;br /&gt;
&lt;br /&gt;
== Building a control-only UI for Vera  ==&lt;br /&gt;
&lt;br /&gt;
If you just want to control Vera, and not modify the configuration, such as with a cell phone interface or web pad, the flow might possibly work like this: &lt;br /&gt;
&lt;br /&gt;
'''1)''' For the initial setup, you need to ask whether the user wants to (a)&amp;amp;nbsp;access Vera remotely with the mios service, and if so, get the user's username/password; or (b) access Vera directly on the home network. You can use locator.php to show the Vera on the home network. You might want to do an auto-detect. For example, you could use locator.php to see if Vera exists locally, and if not, prompt the user for a mios username and password. You can use locator.php and pass the username to get the serial number and internal IP, and then automatically switch to direct access if locator.php (without the username) indicates that serial number is found on the local network. This would allow the user to automatically switch between local access with Wi-Fi (which is much faster of course) and remote access with mios and the mobile phone network.  Or just ask for his mios username and show him all the Vera's he can control, either local or remote.&lt;br /&gt;
&lt;br /&gt;
'''2)''' Once the connection is established, retrieve the list of rooms, scenes, and devices from Vera (see '''user_data''' below). You can cache this data locally so you don't need to retrieve it and parse it over and over.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Present the user with the rooms, scenes, devices.  In Vera's UI's we show first the rooms and then let the user pick a device or scene in the room.  However this data could be presented graphically, such as on a floorplan.  Your UI can have Vera store extra tags and data in the configuration database (ie user_data) to store things like coordinates for icons, outlines or rooms and so on.&lt;br /&gt;
&lt;br /&gt;
'''4)''' If the user picks a scene you can run the scene with the following URL, passing the scene number as '''x''', and it will return an OK if it went okay: &lt;br /&gt;
&lt;br /&gt;
http://127.0.0.1:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=x &lt;br /&gt;
&lt;br /&gt;
'''5)''' If the user picks a device, you use the category which is contained in the user_data to determine what type of controls to present the user. (See [[Luup UPNP Files]] for a list of the categories.) When the user chooses an action, you can send it like this: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
For a list of common actions and device types see: [[Luup CP Mandatory Types]] &lt;br /&gt;
&lt;br /&gt;
Some actions return immediately with an 'OK'. Other jobs may take time to complete and are processed asynchronously.  For these asynchronous jobs you will get a job ID back.  There are several ways to present this to the user.  One possibility is to do what Vera does in the UI, namely to use '''lu_status '''(explained next) to find all active jobs and to put a 'job' icon next to each device to indicate the progress of the job. In this way the user isn't tracking a particular job ''per se'', but just has visual feedback that a device is busy, and if the job icon(s) turn green, that everything went through okay. You could instead track the action individually using the job number that is returned, or use some other method, like making the icon for the device appear animated while it's busy, and turn green or red if the last command succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
'''6)''' Periodically poll the system with '''lu_status''' (explained below), like this: &lt;br /&gt;
&lt;br /&gt;
http://ipaddress:3480/data_request?id=lu_status2&amp;amp;amp;output_format=json &lt;br /&gt;
&lt;br /&gt;
That returns the current values of the UPnP variables, which you can use to show the user current status. For example, if the variable Status is 1 for a switch, you can show the 'on' button in a selected state, while 0 shows it in an 'off' state. '''lu_status''' also shows any active jobs for a device.&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
NOTE: On UI3 builds, user_data2 and user_data are the same, and so is lu_status2 and lu_status. However, on UI2 builds, user_data and lu_status have been deprecated, and you should user_data2 and lu_status2. Therefore, it's best to simply always use user_data2 instead of user_data, and lu_status2 instead of lu_status.&lt;br /&gt;
&lt;br /&gt;
The user_data is the main configuration file that Vera uses to store all the rooms, devices, scenes, timers, events, users, and any other data about the system.  You should request the user_data to get whatever data you need to present to the user, at a minimum, for example, you'll need the list of devices, their descriptions, and the categories (light switch, thermostat, etc.).  You'll also want the list of scenes to present the user.  To fetch the current user_data from Vera use the user_data2 request, like this:&lt;br /&gt;
&lt;br /&gt;
Returns JSON (preferred native format):&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&lt;br /&gt;
&lt;br /&gt;
Returns XML:&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
You can also add a 'DataVersion=TimeStamp' parameter to the URL. It the data has changed since the TimeStamp, all the data is returned. If the data has not changed since the TimeStamp, Vera will return a page with the text 'NO_CHANGES':&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
The user_data contains the state for all the devices.  For example this indicates that the device id #17, called &amp;quot;Switch&amp;quot; is turned off (ie service SwitchPower1, variable Status is 0)&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 17,&lt;br /&gt;
            &amp;quot;category&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;room&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Switch&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;mac&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: &amp;quot;0&amp;quot; &lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
     ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
==lu_status==&lt;br /&gt;
The UPnP variables describe the state of the devices according to the UPnP specs. When the variables change that information needs to be shown to the user, eg change a Switch icon from off to on. If you are interfacing with Vera using the UPnP stack, you can subscribe to the device's events to receive notifications automatically when a device's state changes. However if you're using the web interface you will need to poll using lu_status request.&lt;br /&gt;
&lt;br /&gt;
Call lu_status request like so:&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The returned document contains four sets of information, which constantly change to reflect the current status:&lt;br /&gt;
* root attributes including DataVersion, which is the status timestamp, plus other attributes such as LoadTime &lt;br /&gt;
*the state of the system initialization, such as initialization of the plugin modules.&lt;br /&gt;
*a '''subset''' of the user_data that represents the current state of the device's UPnP variables&lt;br /&gt;
*the status of any active or recent '''jobs''', such as if a light was successfully turned off&lt;br /&gt;
&lt;br /&gt;
===Tracking status changes===&lt;br /&gt;
If you call lu_status without passing a DataVersion on the URL, you will get the current value of all the UPnP variables for a device.  Note that most of the UPnP variables do not ever change.  For example, with a light switch, only the variable &amp;quot;SwitchPower:Status&amp;quot; changes, as the switch is turned off and on.  There are many other variables, like &amp;quot;Capabilities&amp;quot; which are simply configuration data or settings the user modified.  If you pass &amp;amp;DataVersion=1 on the URL, you will only see the UPnP variables which have changed since the Luup engine started.  So, if you parse the initial UPnP variables when you first call user_data, you can call lu_status with DataVersion=1.  Once you call lu_status the first time, store the DataVersion and on subsequent calls pass it on the URL and you will only get the UPnP variables which have changed since that last DataVersion.  Regardless, you will also get the current state of jobs and system initialization.&lt;br /&gt;
&lt;br /&gt;
On subsequent calls to lu_status, you should also pass back in the LoadTime which you received on the prior call.&lt;br /&gt;
&lt;br /&gt;
===Controlling the poll timing===&lt;br /&gt;
You can also pass in a Timeout value, which means the call will block for up to that many seconds if nothing has changed, and will return immediately when something does.  This way you can have infrequent polling, say every 60 seconds by putting a Timeout value of 60, but your UI will be immediately responsive since, when something changes, it returns immediately.  You can also add a MinimumDelay, which means that the call will wait for at least that many milliseconds.  This is advisable so that in the event there are lots of continuous changes, such as a scene turning off many lights, you won't have lu_status calls returning non-stop consuming all the resources on both the Vera and the UI.&lt;br /&gt;
&lt;br /&gt;
===Startup status===&lt;br /&gt;
The section with the initialization tasks is shown in the startup tag as shown:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;startup&amp;quot;: {&lt;br /&gt;
        &amp;quot;tasks&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: 0,&lt;br /&gt;
                &amp;quot;status&amp;quot;: 2,&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;ZWave&amp;quot;,&lt;br /&gt;
                &amp;quot;comments&amp;quot;: &amp;quot;No Z-Wave&amp;quot; &lt;br /&gt;
            },&lt;br /&gt;
&lt;br /&gt;
The startup tasks begin whenever the Luup engine is reset, such as after the user makes a configuration change.  Ever plugin and module in the Luup engine does a startup sequence.  The id is not really important.  The status numbers are the same as for jobs, so 2 means the module failed to startup.  The 'Type' is what you can use to key off of to know which module is being reported, such as &amp;quot;ZWave&amp;quot;, and comments are just notes indicating the current state.  For example, &amp;quot;No Z-Wave&amp;quot; means there's no Z-Wave dongle connected.&lt;br /&gt;
&lt;br /&gt;
Once all the plugins have been initialized successfully the startup section will disappear completely from lu_status.&lt;br /&gt;
&lt;br /&gt;
Note that lu_status also returns UserData_DataVersion, which is the dataversion from user_data.  That way you don't need to poll user_data in parallel.  Simply retrieve the user_data one time at startup, then poll lu_status, and, if UserData_DataVersion is different from the previous user_data you retrieved, then download user_data again.&lt;br /&gt;
&lt;br /&gt;
Some notes on building a full replacement, including configuration, are available here [[UI_Notes_Replacement]], however the syntax is not up to date with the Luup architecture.&lt;br /&gt;
&lt;br /&gt;
===Job status===&lt;br /&gt;
The jobs for a device will look like this:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;Jobs&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;name&amp;quot;: &amp;quot;job#1 :getnodes (0x00D068F0) P:10 S:4&amp;quot;,&lt;br /&gt;
                    &amp;quot;icon&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;4&amp;quot; &lt;br /&gt;
                } &lt;br /&gt;
            ] &lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
The id is the job id number.  When you run an action, like turning on a light, if it happens asynchronously, you'll get a job id number.  All pending jobs for a device are shown by their id number.  The name is just an internal name for the job.  Icon is an optional keyword to indicate what sort of icon should be shown to the user.  For example, 'getnodes' has no icon, meaning this type of job is generally not of interest to a user.  If the icon was 'ON' or 'OFF' that would mean this job is busy turning on or off a light.  Comments is notes about the job, if any.  This may be shown to a user in a tool tip or similar, but is generally more technical than users would care to know.  The status indicates the current state of the job, as shown:&lt;br /&gt;
&lt;br /&gt;
*job_None=-1,  // no icon&lt;br /&gt;
*job_WaitingToStart=0,  // gray icon&lt;br /&gt;
*job_InProgress=1,  // blue icon&lt;br /&gt;
*job_Error=2,  // red icon&lt;br /&gt;
*job_Aborted=3,  // red icon&lt;br /&gt;
*job_Done=4,  // green icon&lt;br /&gt;
*job_WaitingForCallback=5  // blue icon - Special case used in certain derived classes&lt;br /&gt;
&lt;br /&gt;
If the status is 0, this means the job is queued but hasn't started.  If it's 1 or 5 the job is being executed right now.  Generally both 1 and 5 are presented to the user the same way as a 'busy', although technically 1 means Vera is actively talking to the device, and 5 means Vera is waiting for a reply from the device.  Status codes 2, 3 and 4 mean the job has finished.  4 means the job went ok, and both 2 and 3 mean it failed.  Technically 3 means the job was aborted by another job or an external process, like a user cancelling it, while 2 means it failed due to a problem talking to the device.  In both cases this is usually presented the user the same way, as a failure.&lt;br /&gt;
&lt;br /&gt;
== Categories and device types ==&lt;br /&gt;
&lt;br /&gt;
The values used in user_data to determine the types of devices are in [[Luup_UPNP_Files]].  In general you can use the category instead of the devicetype since it's an integer and is thus faster to compare:&lt;br /&gt;
&lt;br /&gt;
== pseudo-code for a UI ==&lt;br /&gt;
&lt;br /&gt;
Here is some pseudo code to show how the polling mechanism should be properly implemented.  The parsing code is, of course, unique to your UI, so placeholder function names are shown here, like FetchAndParse.  This shows the flow for handling the polling so you know you get the changes reported correctly.&lt;br /&gt;
&lt;br /&gt;
 variable int DataVersion_lustatus=0&lt;br /&gt;
 variable int LoadTime=0&lt;br /&gt;
 variable int DataVersion_userdata=0&lt;br /&gt;
&lt;br /&gt;
:START&lt;br /&gt;
  variable boolean FetchUserData=false;&lt;br /&gt;
  if( DataVersion_userdata==0 )  // If we're on the first loop and haven't retrieved user_data, do it and don't do an lu_status&lt;br /&gt;
    FetchUserData=true;&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
     while(true)&lt;br /&gt;
     {&lt;br /&gt;
         newdata = FetchAndParse(&amp;quot;lu_status2&amp;amp;DataVersion=&amp;quot;+DataVersion_lustatus+&amp;quot;&amp;amp;LoadTime=&amp;quot;+LoadTime);&lt;br /&gt;
         if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
            break;  // If we got data, continue on and process it&lt;br /&gt;
        else&lt;br /&gt;
            Sleep 1; // If we didn't get anything, or if lu_status failed, just sleep 1 second and stay in the loop to try again&lt;br /&gt;
     } // End of while loop&lt;br /&gt;
&lt;br /&gt;
     if( newdata.UserData_DataVersion!=DataVersion_userdata )&lt;br /&gt;
     {&lt;br /&gt;
        FetchUserData=true;&lt;br /&gt;
     }&lt;br /&gt;
     else  // Only Parse if userdata is the same, otherwise we're going to reload user_data&lt;br /&gt;
     {&lt;br /&gt;
        ParseLuStatus();  // This won't run if user_data has changed&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
      }&lt;br /&gt;
  }  // end of else loop&lt;br /&gt;
&lt;br /&gt;
 if( FetchUserData==true )&lt;br /&gt;
{&lt;br /&gt;
   UI.HourglassAndSuspend(true); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
   newdata = FetchAndParse(&amp;quot;user_data2&amp;quot;);&lt;br /&gt;
    if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
    {&lt;br /&gt;
        ParseUserData();&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
         LoadTime=newdata.LoadTime&lt;br /&gt;
         DataVersion_userdata=newdata.DataVersion&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
       UI.DisplayError(&amp;quot;Failed to update data&amp;quot;); // Display in the info panel an error message that the user will see for 10 seconds or so&lt;br /&gt;
&lt;br /&gt;
   UI.HourglassAndSuspend(false); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Sleep 1; // We know we just parsed user_data or lu_status, so sleep before looping&lt;br /&gt;
goto START; // Loop again and start over&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/UI_Notes</id>
		<title>UI Notes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/UI_Notes"/>
				<updated>2015-06-04T12:04:24Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Tracking status changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
Here is some general information about getting information to display in a user interface:&lt;br /&gt;
&lt;br /&gt;
== UPnP messaging system  ==&lt;br /&gt;
&lt;br /&gt;
Vera uses UPnP for all the messaging, such as turning lights on and off.  So Vera translates Z-Wave, Insteon, infrared codes, etc., into UPnP actions. If you have already implemented a UPnP stack and can send properly formated UPnP SOAP/XML requests, you can control everything using standard UPnP action invocation. If you did not, Vera provides a simple HTTP GET interface as well, which is discussed below.&lt;br /&gt;
&lt;br /&gt;
In a nutshell UPnP works like this: You have UPnP devices, which are things that can be controlled and can report their state, like a light switch.  And you have UPnP Control Points, which are the things that let a user control UPnP devices, like a touch-screen web pad.  The Control Point does this by a) reading the device and descriptions for the UPnP device to see what it can do, and b) invoking actions on the UPnP device (ie telling it to do something), and c) reading and setting variables for the device which describe the current state and/or configuration settings for the device.&lt;br /&gt;
&lt;br /&gt;
A UPnP device is defined in an XML document called a device description document.  To see one, in Vera's setup UI, go to Devices, Luup plugins, Luup Files, and click 'view' file next to D_BinaryLight1.xml.  Use Firefox since it has a built-in XML viewer.  Notice the tag: &amp;lt;deviceType&amp;gt;urn:schemas-upnp-org:device:BinaryLight:1&amp;lt;/deviceType&amp;gt;.  This defines the type of device, namely an on/off light switch, which is what you use to know how to represent this device to a user.  A device optionally implements one or more services.  In this case the services: urn:upnp-org:serviceId:SwitchPower1, urn:micasaverde-com:serviceId:EnergyMetering1 and urn:micasaverde-com:serviceId:HaDevice1.&lt;br /&gt;
&lt;br /&gt;
A service is a collection of actions which a device implement and which you can invoke from a UPnP Control Point, as well as a collection of variables which always have a current value.  The variables describe the current state of the device and/or configuration settings.  View the file S_SwitchPower1.xml to see a service.  For example, the device urn:schemas-upnp-org:device:BinaryLight:1 implements the service urn:upnp-org:serviceId:SwitchPower1, which has the action SetTarget, which is how you turn the light on and off.  The action takes a single argument newTargetValue which can be 0 to turn the light off and 1 to turn it on.  The service also has the variable Status which is 0 or 1 depending on whether the light is currently on or off.&lt;br /&gt;
&lt;br /&gt;
If you open the device description for a dimmable light D_DimmableLight1.xml you'll see that it implements the same service S_SwitchPower1.xml, since you can still turn it on and off, and it also implements the service urn:upnp-org:serviceId:Dimming1, which has an action to set the dim level (SetLoadLevelTarget).&lt;br /&gt;
&lt;br /&gt;
To test UPnP calls you can use the Intel Device Spy utility available [http://www.intel.com/cd/ids/developer/asmo-na/eng/downloads/upnp/tools/218896.htm?desturl=http://softwarecommunity.intel.com/isn/downloads/zips/IntelToolsForUPnPTechnology_v2.zip here].  It should pick up Vera, show you all the devices, like light switches, thermostats, etc., let you expand the services and see the actions and variables.  Click an action, like SetTarget, to specify the arguments and click 'Invoke' to run the action, such as turning on and off the light.&lt;br /&gt;
&lt;br /&gt;
== JSON vs. XML ==&lt;br /&gt;
&lt;br /&gt;
The native UPnP protocol uses XML/SOAP.  But there are also several times you will request data from Vera that has nothing to do with the UPnP spec.  These will be done with data_request's as explained below, such as user_data, lu_status, etc.  Internally Vera uses JSON as the native format, but Vera can convert to XML (details follow).  In general when you want to view data in a human readable format, such as the device list, it's easiest to use the Firefox browser, and request Vera convert the data to XML.  Firefox has a nice browser to display XML in human readable format.  If you want to make the JSON data nicely formatted, you can use the web site jsonlint.com.  In a UI application which will request data regularly from Vera we recommend retrieving everything in JSON format, not XML, because Vera's CPU is not that powerful and so continuous requests of data in XML format will cause a lot of CPU time to be devoted to converting JSON into XML.&lt;br /&gt;
&lt;br /&gt;
== Finding Vera on the local network  ==&lt;br /&gt;
&lt;br /&gt;
You can find Vera by using the traditional UPnP discovery process, or you can retrieve this URL:&amp;lt;br&amp;gt;'''https://sta1.mios.com/locator_json.php?username=xxx''' where the username=xxx is optional, but, if specified, it will report all systems that mios.com user xxx can report whether local or remote, and without the username=xxx it only shows the Vera's on the user's local home network.&lt;br /&gt;
&lt;br /&gt;
Each Vera, when it boots up, reports its internal IP address to the central mios.com server, which tracks this along with the external IP address. '''locator.php''' shows all serial numbers and internal network IP addresses on the same external IP. For example, if '''https://sta1.mios.com/locator_json.php?username=xxx'''.&lt;br /&gt;
&lt;br /&gt;
== The HTTP interface  ==&lt;br /&gt;
&lt;br /&gt;
Vera listens on port 3480. Vera responds to UPnP actions the normal way, or by making simple HTTP requests. For example, to turn on a light you can either send the UPnP action &amp;quot;SetTarget&amp;quot; to the device using the normal UPnP mechanism, or you can simply put this URL in your web browser, or with wget, or similar: &lt;br /&gt;
&lt;br /&gt;
http://[ipadress]:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
That URL will return the same results of the action as using the normal UPnP architecture. The '''output_format=xml''' on the URL means the data returned should be in XML format. You can instead use '''output_format=json'''&lt;br /&gt;
&lt;br /&gt;
The service ID's, actions, and arguments are all defined by the UPnP forum.  A list of ratified UPnP devices and services is available on the [http://www.upnp.org UPnP Forum].  Mi Casa Verde added its own custom devices and services when there was no existing UPnP standard.  A list of these can be found in the [[Luup_UPNP_Files]] header files.&lt;br /&gt;
&lt;br /&gt;
== Getting the system configuration  ==&lt;br /&gt;
&lt;br /&gt;
Either use the UPnP service/action:&amp;lt;br&amp;gt; '''urn:micasaverde-com:serviceId:HomeAutomationGateway1/GetUserData''' &lt;br /&gt;
&lt;br /&gt;
or use the built-in request: &lt;br /&gt;
&lt;br /&gt;
'''http://ipaddress:3480/data_request?id=user_data2&amp;amp;amp;output_format=json''' (or xml) &lt;br /&gt;
&lt;br /&gt;
This returns the system configuration file for Vera. It's assumed you understand the way Vera categorizes devices with Rooms, Devices, Scenes, etc. When creating a user interface for controlling Vera only, like on a mobile phone, most of the tags can be ignored, since usually you just need the list of rooms and devices.&lt;br /&gt;
&lt;br /&gt;
== Accessing Vera remotely through the mios server ==&lt;br /&gt;
&lt;br /&gt;
Native UPnP only works on a local area home network, and cannot be used over the Internet.  The mios server provides a secure way to remotely access and control your Vera system using the HTTP interface without having to make any substantial changes to the UI.  Everything you can do locally with Vera on port 3480, you can do remotely with mios using the exact same syntax.  You only need to ask the user for his username and password and pass them on the URL to the remote access server, along with the serial number of the unit (ie like 12345).  For example, the above user_data is the syntax for local access on a home network.  To retrieve the same URL over the internet with mios use:&lt;br /&gt;
&lt;br /&gt;
https://fwd2.mios.com/demovera/myvera123/12345/data_request?id=lu_status&amp;amp;output_format=json (or use fwd1.mios.com)&lt;br /&gt;
&lt;br /&gt;
assuming demovera is the username and myvera123 is the password that the user chose setting up his mios.com account.  Note that since the request is https, the username and password are encrypted because https encrypts the URL's as well as the contents of the page.&lt;br /&gt;
&lt;br /&gt;
== Building a control-only UI for Vera  ==&lt;br /&gt;
&lt;br /&gt;
If you just want to control Vera, and not modify the configuration, such as with a cell phone interface or web pad, the flow might possibly work like this: &lt;br /&gt;
&lt;br /&gt;
'''1)''' For the initial setup, you need to ask whether the user wants to (a)&amp;amp;nbsp;access Vera remotely with the mios service, and if so, get the user's username/password; or (b) access Vera directly on the home network. You can use locator.php to show the Vera on the home network. You might want to do an auto-detect. For example, you could use locator.php to see if Vera exists locally, and if not, prompt the user for a mios username and password. You can use locator.php and pass the username to get the serial number and internal IP, and then automatically switch to direct access if locator.php (without the username) indicates that serial number is found on the local network. This would allow the user to automatically switch between local access with Wi-Fi (which is much faster of course) and remote access with mios and the mobile phone network.  Or just ask for his mios username and show him all the Vera's he can control, either local or remote.&lt;br /&gt;
&lt;br /&gt;
'''2)''' Once the connection is established, retrieve the list of rooms, scenes, and devices from Vera (see '''user_data''' below). You can cache this data locally so you don't need to retrieve it and parse it over and over.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Present the user with the rooms, scenes, devices.  In Vera's UI's we show first the rooms and then let the user pick a device or scene in the room.  However this data could be presented graphically, such as on a floorplan.  Your UI can have Vera store extra tags and data in the configuration database (ie user_data) to store things like coordinates for icons, outlines or rooms and so on.&lt;br /&gt;
&lt;br /&gt;
'''4)''' If the user picks a scene you can run the scene with the following URL, passing the scene number as '''x''', and it will return an OK if it went okay: &lt;br /&gt;
&lt;br /&gt;
http://127.0.0.1:3480/data_request?id=lu_action&amp;amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;amp;action=RunScene&amp;amp;amp;SceneNum=x &lt;br /&gt;
&lt;br /&gt;
'''5)''' If the user picks a device, you use the category which is contained in the user_data to determine what type of controls to present the user. (See [[Luup UPNP Files]] for a list of the categories.) When the user chooses an action, you can send it like this: &lt;br /&gt;
&lt;br /&gt;
http://ipadress:3480/data_request?id=lu_action&amp;amp;amp;output_format=xml&amp;amp;amp;DeviceNum=10&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;
For a list of common actions and device types see: [[Luup CP Mandatory Types]] &lt;br /&gt;
&lt;br /&gt;
Some actions return immediately with an 'OK'. Other jobs may take time to complete and are processed asynchronously.  For these asynchronous jobs you will get a job ID back.  There are several ways to present this to the user.  One possibility is to do what Vera does in the UI, namely to use '''lu_status '''(explained next) to find all active jobs and to put a 'job' icon next to each device to indicate the progress of the job. In this way the user isn't tracking a particular job ''per se'', but just has visual feedback that a device is busy, and if the job icon(s) turn green, that everything went through okay. You could instead track the action individually using the job number that is returned, or use some other method, like making the icon for the device appear animated while it's busy, and turn green or red if the last command succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
'''6)''' Periodically poll the system with '''lu_status''' (explained below), like this: &lt;br /&gt;
&lt;br /&gt;
http://ipaddress:3480/data_request?id=lu_status2&amp;amp;amp;output_format=json &lt;br /&gt;
&lt;br /&gt;
That returns the current values of the UPnP variables, which you can use to show the user current status. For example, if the variable Status is 1 for a switch, you can show the 'on' button in a selected state, while 0 shows it in an 'off' state. '''lu_status''' also shows any active jobs for a device.&lt;br /&gt;
&lt;br /&gt;
==user_data==&lt;br /&gt;
NOTE: On UI3 builds, user_data2 and user_data are the same, and so is lu_status2 and lu_status. However, on UI2 builds, user_data and lu_status have been deprecated, and you should user_data2 and lu_status2. Therefore, it's best to simply always use user_data2 instead of user_data, and lu_status2 instead of lu_status.&lt;br /&gt;
&lt;br /&gt;
The user_data is the main configuration file that Vera uses to store all the rooms, devices, scenes, timers, events, users, and any other data about the system.  You should request the user_data to get whatever data you need to present to the user, at a minimum, for example, you'll need the list of devices, their descriptions, and the categories (light switch, thermostat, etc.).  You'll also want the list of scenes to present the user.  To fetch the current user_data from Vera use the user_data2 request, like this:&lt;br /&gt;
&lt;br /&gt;
Returns JSON (preferred native format):&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&lt;br /&gt;
&lt;br /&gt;
Returns XML:&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
You can also add a 'DataVersion=TimeStamp' parameter to the URL. It the data has changed since the TimeStamp, all the data is returned. If the data has not changed since the TimeStamp, Vera will return a page with the text 'NO_CHANGES':&lt;br /&gt;
&lt;br /&gt;
http://[ip address]:3480/data_request?id=user_data2&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
The user_data contains the state for all the devices.  For example this indicates that the device id #17, called &amp;quot;Switch&amp;quot; is turned off (ie service SwitchPower1, variable Status is 0)&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 17,&lt;br /&gt;
            &amp;quot;category&amp;quot;: 3,&lt;br /&gt;
            &amp;quot;room&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;Switch&amp;quot;,&lt;br /&gt;
            &amp;quot;ip&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;mac&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: &amp;quot;0&amp;quot; &lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
     ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
==lu_status==&lt;br /&gt;
The UPnP variables describe the state of the devices according to the UPnP specs. When the variables change that information needs to be shown to the user, eg change a Switch icon from off to on. If you are interfacing with Vera using the UPnP stack, you can subscribe to the device's events to receive notifications automatically when a device's state changes. However if you're using the web interface you will need to poll using lu_status request.&lt;br /&gt;
&lt;br /&gt;
Call lu_status request like so:&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status2&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status2&amp;amp;output_format=xml&lt;br /&gt;
&lt;br /&gt;
:http://[ip address]:3480/data_request?id=lu_status2&amp;amp;DataVersion=315587159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The returned document contains four sets of information, which constantly change to reflect the current status:&lt;br /&gt;
* root attributes including DataVersion, which is the status timestamp, plus other attributes such as LoadTime &lt;br /&gt;
*the state of the system initialization, such as initialization of the plugin modules.&lt;br /&gt;
*a '''subset''' of the user_data that represents the current state of the device's UPnP variables&lt;br /&gt;
*the status of any active or recent '''jobs''', such as if a light was successfully turned off&lt;br /&gt;
&lt;br /&gt;
===Tracking status changes===&lt;br /&gt;
If you call lu_status without passing a DataVersion on the URL, you will get the current value of all the UPnP variables for a device.  Note that most of the UPnP variables do not ever change.  For example, with a light switch, only the variable &amp;quot;SwitchPower:Status&amp;quot; changes, as the switch is turned off and on.  There are many other variables, like &amp;quot;Capabilities&amp;quot; which are simply configuration data or settings the user modified.  If you pass &amp;amp;DataVersion=1 on the URL, you will only see the UPnP variables which have changed since the Luup engine started.  So, if you parse the initial UPnP variables when you first call user_data, you can call lu_status with DataVersion=1.  Once you call lu_status the first time, store the DataVersion and on subsequent calls pass it on the URL and you will only get the UPnP variables which have changed since that last DataVersion.  Regardless, you will also get the current state of jobs and system initialization.&lt;br /&gt;
&lt;br /&gt;
On subsequent calls to lu_status, you should also pass back in the LoadTime which you received on the prior call.&lt;br /&gt;
&lt;br /&gt;
===Controlling the poll timing===&lt;br /&gt;
You can also pass in a Timeout value, which means the call will block for up to that many seconds if nothing has changed, and will return immediately when something does.  This way you can have infrequent polling, say every 60 seconds by putting a Timeout value of 60, but your UI will be immediately responsive since, when something changes, it returns immediately.  You can also add a MinimumDelay, which means that the call will wait for at least that many milliseconds.  This is advisable so that in the event there are lots of continuous changes, such as a scene turning off many lights, you won't have lu_status2 calls returning non-stop consuming all the resources on both the Vera and the UI.&lt;br /&gt;
&lt;br /&gt;
===Startup status===&lt;br /&gt;
The section with the initialization tasks is shown in the startup tag as shown:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;startup&amp;quot;: {&lt;br /&gt;
        &amp;quot;tasks&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;id&amp;quot;: 0,&lt;br /&gt;
                &amp;quot;status&amp;quot;: 2,&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;ZWave&amp;quot;,&lt;br /&gt;
                &amp;quot;comments&amp;quot;: &amp;quot;No Z-Wave&amp;quot; &lt;br /&gt;
            },&lt;br /&gt;
&lt;br /&gt;
The startup tasks begin whenever the Luup engine is reset, such as after the user makes a configuration change.  Ever plugin and module in the Luup engine does a startup sequence.  The id is not really important.  The status numbers are the same as for jobs, so 2 means the module failed to startup.  The 'Type' is what you can use to key off of to know which module is being reported, such as &amp;quot;ZWave&amp;quot;, and comments are just notes indicating the current state.  For example, &amp;quot;No Z-Wave&amp;quot; means there's no Z-Wave dongle connected.&lt;br /&gt;
&lt;br /&gt;
Once all the plugins have been initialized successfully the startup section will disappear completely from lu_status.&lt;br /&gt;
&lt;br /&gt;
Note that lu_status2 also returns UserData_DataVersion, which is the dataversion from user_data.  That way you don't need to poll user_data in parallel.  Simply retrieve the user_data one time at startup, then poll lu_status, and, if UserData_DataVersion is different from the previous user_data you retrieved, then download user_data again.&lt;br /&gt;
&lt;br /&gt;
Some notes on building a full replacement, including configuration, are available here [[UI_Notes_Replacement]], however the syntax is not up to date with the Luup architecture.&lt;br /&gt;
&lt;br /&gt;
===Job status===&lt;br /&gt;
The jobs for a device will look like this:&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;devices&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;Jobs&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                    &amp;quot;name&amp;quot;: &amp;quot;job#1 :getnodes (0x00D068F0) P:10 S:4&amp;quot;,&lt;br /&gt;
                    &amp;quot;icon&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;comments&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
                    &amp;quot;status&amp;quot;: &amp;quot;4&amp;quot; &lt;br /&gt;
                } &lt;br /&gt;
            ] &lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
The id is the job id number.  When you run an action, like turning on a light, if it happens asynchronously, you'll get a job id number.  All pending jobs for a device are shown by their id number.  The name is just an internal name for the job.  Icon is an optional keyword to indicate what sort of icon should be shown to the user.  For example, 'getnodes' has no icon, meaning this type of job is generally not of interest to a user.  If the icon was 'ON' or 'OFF' that would mean this job is busy turning on or off a light.  Comments is notes about the job, if any.  This may be shown to a user in a tool tip or similar, but is generally more technical than users would care to know.  The status indicates the current state of the job, as shown:&lt;br /&gt;
&lt;br /&gt;
*job_None=-1,  // no icon&lt;br /&gt;
*job_WaitingToStart=0,  // gray icon&lt;br /&gt;
*job_InProgress=1,  // blue icon&lt;br /&gt;
*job_Error=2,  // red icon&lt;br /&gt;
*job_Aborted=3,  // red icon&lt;br /&gt;
*job_Done=4,  // green icon&lt;br /&gt;
*job_WaitingForCallback=5  // blue icon - Special case used in certain derived classes&lt;br /&gt;
&lt;br /&gt;
If the status is 0, this means the job is queued but hasn't started.  If it's 1 or 5 the job is being executed right now.  Generally both 1 and 5 are presented to the user the same way as a 'busy', although technically 1 means Vera is actively talking to the device, and 5 means Vera is waiting for a reply from the device.  Status codes 2, 3 and 4 mean the job has finished.  4 means the job went ok, and both 2 and 3 mean it failed.  Technically 3 means the job was aborted by another job or an external process, like a user cancelling it, while 2 means it failed due to a problem talking to the device.  In both cases this is usually presented the user the same way, as a failure.&lt;br /&gt;
&lt;br /&gt;
== Categories and device types ==&lt;br /&gt;
&lt;br /&gt;
The values used in user_data to determine the types of devices are in [[Luup_UPNP_Files]].  In general you can use the category instead of the devicetype since it's an integer and is thus faster to compare:&lt;br /&gt;
&lt;br /&gt;
== pseudo-code for a UI ==&lt;br /&gt;
&lt;br /&gt;
Here is some pseudo code to show how the polling mechanism should be properly implemented.  The parsing code is, of course, unique to your UI, so placeholder function names are shown here, like FetchAndParse.  This shows the flow for handling the polling so you know you get the changes reported correctly.&lt;br /&gt;
&lt;br /&gt;
 variable int DataVersion_lustatus=0&lt;br /&gt;
 variable int LoadTime=0&lt;br /&gt;
 variable int DataVersion_userdata=0&lt;br /&gt;
&lt;br /&gt;
:START&lt;br /&gt;
  variable boolean FetchUserData=false;&lt;br /&gt;
  if( DataVersion_userdata==0 )  // If we're on the first loop and haven't retrieved user_data, do it and don't do an lu_status&lt;br /&gt;
    FetchUserData=true;&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
     while(true)&lt;br /&gt;
     {&lt;br /&gt;
         newdata = FetchAndParse(&amp;quot;lu_status2&amp;amp;DataVersion=&amp;quot;+DataVersion_lustatus+&amp;quot;&amp;amp;LoadTime=&amp;quot;+LoadTime);&lt;br /&gt;
         if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
            break;  // If we got data, continue on and process it&lt;br /&gt;
        else&lt;br /&gt;
            Sleep 1; // If we didn't get anything, or if lu_status failed, just sleep 1 second and stay in the loop to try again&lt;br /&gt;
     } // End of while loop&lt;br /&gt;
&lt;br /&gt;
     if( newdata.UserData_DataVersion!=DataVersion_userdata )&lt;br /&gt;
     {&lt;br /&gt;
        FetchUserData=true;&lt;br /&gt;
     }&lt;br /&gt;
     else  // Only Parse if userdata is the same, otherwise we're going to reload user_data&lt;br /&gt;
     {&lt;br /&gt;
        ParseLuStatus();  // This won't run if user_data has changed&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
      }&lt;br /&gt;
  }  // end of else loop&lt;br /&gt;
&lt;br /&gt;
 if( FetchUserData==true )&lt;br /&gt;
{&lt;br /&gt;
   UI.HourglassAndSuspend(true); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
   newdata = FetchAndParse(&amp;quot;user_data2&amp;quot;);&lt;br /&gt;
    if( newdata.IsEmpty()==false &amp;amp;&amp;amp; newdata.isError()==false )&lt;br /&gt;
    {&lt;br /&gt;
        ParseUserData();&lt;br /&gt;
        DataVersion_lustatus=newdata.DataVersion&lt;br /&gt;
         LoadTime=newdata.LoadTime&lt;br /&gt;
         DataVersion_userdata=newdata.DataVersion&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
       UI.DisplayError(&amp;quot;Failed to update data&amp;quot;); // Display in the info panel an error message that the user will see for 10 seconds or so&lt;br /&gt;
&lt;br /&gt;
   UI.HourglassAndSuspend(false); // Put a 'busy' hourglass in the UI, display a message in the info panel &amp;quot;Updating data&amp;quot; and suspend all UI stuff since this may take a moment&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Sleep 1; // We know we just parsed user_data or lu_status, so sleep before looping&lt;br /&gt;
goto START; // Loop again and start over&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MyDevice5.jpg</id>
		<title>File:MyDevice5.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MyDevice5.jpg"/>
				<updated>2015-03-10T10:33:56Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MyDevice4.jpg</id>
		<title>File:MyDevice4.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MyDevice4.jpg"/>
				<updated>2015-03-10T10:33:43Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MyDevice3.jpg</id>
		<title>File:MyDevice3.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MyDevice3.jpg"/>
				<updated>2015-03-10T10:33:25Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MyDevice2.jpg</id>
		<title>File:MyDevice2.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MyDevice2.jpg"/>
				<updated>2015-03-10T10:31:00Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugins:_Static_JSON_file</id>
		<title>Luup plugins: Static JSON file</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugins:_Static_JSON_file"/>
				<updated>2015-03-10T10:30:20Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
Starting in UI4, Luup plugins can specify a ''static JSON'' file.  This file describes how the plugin appears in the web interface.&lt;br /&gt;
&lt;br /&gt;
=What the static JSON file controls=&lt;br /&gt;
&lt;br /&gt;
* The icon used by the plugin in the dashboard.&lt;br /&gt;
* The text that displays in the one-to-two-row status message in the dashboard.&lt;br /&gt;
* Whether the icon changes depending on the value of a variable in the device (for example, a binary light's icon changes from lit to unlit).&lt;br /&gt;
* The tabs that appear in the device's detail dialog (when you click the wrench/spanner).&lt;br /&gt;
* The content of these tabs.&lt;br /&gt;
* The triggers or events that are available for the device in the &amp;quot;Triggers&amp;quot; or &amp;quot;Events&amp;quot; tag of a scene.&lt;br /&gt;
&lt;br /&gt;
=Referencing the static JSON file from the Device XML file=&lt;br /&gt;
&lt;br /&gt;
The device XML file (customarly '''D_PluginName.xml''') contains a reference to the static JSON file, in the '''staticJson''' element.  Place the element as a child of the '''device''' element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
  &amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
  &amp;lt;root xmlns=&amp;quot;urn:schemas-upnp-org:device-1-0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;specVersion&amp;gt;&amp;lt;!-- ... --&amp;gt;&amp;lt;/specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;device&amp;gt;&lt;br /&gt;
      &amp;lt;deviceType&amp;gt;urn:schemas-futzle-com:device:holidayvirtualswitch:1&amp;lt;/deviceType&amp;gt;&lt;br /&gt;
      &amp;lt;staticJson&amp;gt;D_HolidayVirtualSwitch1.json&amp;lt;/staticJson&amp;gt;&lt;br /&gt;
      &amp;lt;!-- ... --&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Capitalization is important, as with all XML.&lt;br /&gt;
&lt;br /&gt;
The static JSON file is customarily called '''D_PluginName.json'''.&lt;br /&gt;
&lt;br /&gt;
=The static JSON file=&lt;br /&gt;
&lt;br /&gt;
The static JSON file is a single JSON object (associative array).&lt;br /&gt;
&lt;br /&gt;
==Root keys==&lt;br /&gt;
&lt;br /&gt;
These keys have been seen at the top level in static JSON files in the wild:&lt;br /&gt;
&lt;br /&gt;
; flashicon&lt;br /&gt;
: The device's icon, as a string.  Despite the name, the icon is no longer related to Adobe Flash in UI4 or UI5. See [[Luup plugin icons]].&lt;br /&gt;
; imgIconBody&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconDimmable&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconTurnable&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconMin&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconMax&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; halloIconsDir&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; inScene&lt;br /&gt;
: When included and set equal to one, it enables any buttons, etc located on the &amp;quot;dashboard box&amp;quot;, so they can be selected in the scene editor for use in scenes, rather than being grayed out.&lt;br /&gt;
; DisplayStatus&lt;br /&gt;
: A JSON object (associative array).  For devices where the icon changes based on a variable's value, describes which variable, and the range of values that produce different icon images.  See [[Luup plugin icons]].&lt;br /&gt;
; state_icons&lt;br /&gt;
: A JSON array.  For devices where the icon changes based on a variable's value, describes which icon files exist.  See [[Luup plugin icons]]. Used only in firmware 1.5.401 or later.&lt;br /&gt;
; doc_url&lt;br /&gt;
: A JSON object (associative array). In UI5, the only item in this object which is used is doc_page. It controls which page in docs5.mios.com is brought up when you click on the help ('''?''') icon in the device control panel.&lt;br /&gt;
; Tabs&lt;br /&gt;
: A JSON array.  Describes the tabs in the detail dialog, and what subset of the first tab appears in the dashboard.  See [[Luup plugin tabs]].&lt;br /&gt;
; ToggleButton&lt;br /&gt;
: ?????&lt;br /&gt;
; DeviceType&lt;br /&gt;
: A JSON string.  Must match the '''deviceType''' element in the corresponding device XML ('''D_PluginName.xml''') file.&lt;br /&gt;
; eventList&lt;br /&gt;
: A JSON object (associative array).  Describes the events that this plugin can produce.  Events are triggers that can fire off actions in scenes.  This key is required for UI4, and obsoleted in UI5. For UI5, use the eventList2 tag, which has a different format. For compatibility with both UI4 and UI5 you need the same information in both keys. See [[UI4 UI5 Migration]] for more information.&lt;br /&gt;
; eventList2&lt;br /&gt;
: see eventList, above.&lt;br /&gt;
; sceneList&lt;br /&gt;
: A JSON object (associative array).  Describes the actions that this plugin can perform (for instance, as the action in a scene). This key is not required and is ignored in UI5, however it is needed for UI4 compatibility. See [[UI4 UI5 Migration]] for more information about its format.&lt;br /&gt;
&lt;br /&gt;
= UI7 Updates =&lt;br /&gt;
&lt;br /&gt;
* '''default_icon'''&lt;br /&gt;
: replace the old &amp;quot;flashicon&amp;quot; from UI5. See [[Luup plugin icons]]&lt;br /&gt;
* '''state_icons'''&lt;br /&gt;
: state_icons mechanism has changed in UI7. Please see [[Luup plugin icons]]&lt;br /&gt;
* '''TopNavigationTab''' = '''top_navigation_tab'''&lt;br /&gt;
&lt;br /&gt;
In device cpanel, tabs can be placed either in the top part or in the bottom. By default they are put in the bottom part. You can mark your tabs with a special flag so that they can be placed in top navigation bar of the cpanel.&lt;br /&gt;
If two or more tabs are marked with ‘'''TabType=”flash”'''’, only the first one found will be placed in top navigation bar. If you want all of them to be placed there, you have to add ‘'''top_navigation_tab'''’ to each one.&lt;br /&gt;
Let’s assume you have a plugin named ‘MyPlugin’ and you want to put a button in the top navigation bar, which, when clicked, will display a message in the cpanel.&lt;br /&gt;
&lt;br /&gt;
* Add the following lines to the .json device file (D_MyPlugin.json), in the Tabs section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
          &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;About&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;About&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
              &amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
          &amp;quot;Position&amp;quot;: &amp;quot;4&amp;quot;,&lt;br /&gt;
          &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
          &amp;quot;ScriptName&amp;quot;: &amp;quot;J_MyPlugin.js&amp;quot;,&lt;br /&gt;
          &amp;quot;Function&amp;quot;: &amp;quot;MyPlugin.about&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice the property ‘'''TopNavigationTab'''’ set to the value of ‘1’. This is the line that specifies where to place the tab in cpanel. If you set a value different than 1, the tab will be placed in the bottom part of the cpanel, so always use ‘1’ if you want the tab in the top bar. You can also use ‘'''top_navigation_tab'''’.&lt;br /&gt;
&lt;br /&gt;
* Add the following lines of code to your .js file (J_MyPlugin.js):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function(api){&lt;br /&gt;
    return {&lt;br /&gt;
        about: function() {&lt;br /&gt;
            try {              &lt;br /&gt;
                var html = '&amp;lt;div&amp;gt;This is all about me !&amp;lt;/div&amp;gt;';&lt;br /&gt;
             api.setCpanelContent(html);&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                Utils.logError('Error in MyPlugin.about(): ' + e);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Perform a lu reload, enter device cpanel and click on ‘About’ button (which is in the top navigation bar of the cpanel) and the result will be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:TopNavigationTab.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Position device controls for generic devices ==&lt;br /&gt;
&lt;br /&gt;
In UI7, devices are split into two categories: specific and generic. Specific devices are those which have a predefined design (like binary light, thermostat, dimmable etc.). Generic devices are those created by plugin developers.&lt;br /&gt;
&lt;br /&gt;
=== Positioning controls in ‘device view’ ===&lt;br /&gt;
&lt;br /&gt;
The controls for generic devices are placed inside the device container based on the order in which are found in device .json file and so, each control is drawn to the right of the previous one. If a control doesn’t fit in the remaining space it will be drawn on the following line. This rule will guarantee that the look of a device will be the same on the Web, but also on the mobile apps.&lt;br /&gt;
&lt;br /&gt;
In order to achieve this, but also to maintain backward compatibility with UI5, the developer can add new properties to the device .json, but doesn’t have to change the existing ones.&lt;br /&gt;
&lt;br /&gt;
In the WEB UI, each control is contained in a div element which is positioned using float: left CSS property.&lt;br /&gt;
&lt;br /&gt;
The size of the controls can be altered using properties like ‘HorizontalMultiplier’ which multiplies the default width of a control with a given float number.&lt;br /&gt;
&lt;br /&gt;
To force a control to be positioned on the next line, a special device control was created: ‘line_break’.&lt;br /&gt;
&lt;br /&gt;
To insert a space between two controls, the developer can use the newly created device control: ‘spacer’, which also accepts ‘HorizontalMultiplier’ property.&lt;br /&gt;
&lt;br /&gt;
=== Tutorial ===&lt;br /&gt;
&lt;br /&gt;
We will start with a device that contains no controls.&lt;br /&gt;
&lt;br /&gt;
* First, we need a SceneGroup with id 1 and a ControlGroup with id 1 which belongs to the previous added scene group (this is the same as in UI5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;SceneGroup&amp;quot;: [&lt;br /&gt;
   {&lt;br /&gt;
       &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;top&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;left&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
       &amp;quot;x&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
       &amp;quot;y&amp;quot;: &amp;quot;3&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
],&lt;br /&gt;
&amp;quot;ControlGroup&amp;quot;: [&lt;br /&gt;
   {&lt;br /&gt;
       &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;isSingle&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;scenegroup&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Then, add a control of type ‘button’ with a label: ‘My First Button’. Create it using the same definition as in UI5. Be sure to set the ControlGroup of the button to be equal to 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;my_button&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;my_first_button&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;My First Button&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* By now, your device will look something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:MyDevice1.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
* Notice that the text doesn’t fit properly inside the button. Add &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;2&amp;quot; property to your control definition. This will set the width of the button to double the default size. By now, your device will look like this:&lt;br /&gt;
&lt;br /&gt;
[[File:MyDevice2.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
* Add 6 more buttons using the same template as above, but don’t set the “HorizontalMultiplier” property. Use labels: ‘Button 1’, ‘Button 2’, … ‘Button 6’. It will look like this:&lt;br /&gt;
&lt;br /&gt;
[[File:MyDevice3.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
* Notice that the latest 6 buttons will be added to the right of the previously added ones; if the button doesn’t fit in the remaining space it will be placed on the next line&lt;br /&gt;
&lt;br /&gt;
* We decide to move buttons 1-3 on a separate line and buttons 4-6 on another line; to do so, add a control of type ‘line_break’ at the end of ‘My First Button’ and at the end of ‘Button 3’. The syntax is the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;line_break&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* And the result is like this:&lt;br /&gt;
&lt;br /&gt;
[[File:MyDevice4.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
* If you want some space between the buttons you can use ‘spacer’, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;spacer&amp;quot;,&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;0.7&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The result:&lt;br /&gt;
&lt;br /&gt;
[[File:MyDevice5.jpg|image|center|caption]]&lt;br /&gt;
&lt;br /&gt;
* Here is the full definition of the Control array (highlighted with blue you can see UI7 specific properties):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;my_button&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;my_first_button&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;My First Button&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;line_break&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_1&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button1&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button1&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;21&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;21&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;spacer&amp;quot;,&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;0.7&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_2&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button2&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button2&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;22&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;22&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;spacer&amp;quot;,&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;0.7&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_3&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button3&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button3&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;23&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;23&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;line_break&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_4&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button4&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button4&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;24&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;24&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;spacer&amp;quot;,&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;0.7&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_5&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button5&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button5&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;25&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;25&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;spacer&amp;quot;,&lt;br /&gt;
   &amp;quot;HorizontalMultiplier&amp;quot;: &amp;quot;0.7&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;ControlGroup&amp;quot;: 1,&lt;br /&gt;
   &amp;quot;ControlType&amp;quot;: &amp;quot;button&amp;quot;,&lt;br /&gt;
   &amp;quot;ControlCode&amp;quot;: &amp;quot;button_6&amp;quot;,&lt;br /&gt;
   &amp;quot;top&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;left&amp;quot;: 0,&lt;br /&gt;
   &amp;quot;Label&amp;quot;: {&lt;br /&gt;
       &amp;quot;lang_tag&amp;quot;: &amp;quot;button6&amp;quot;,&lt;br /&gt;
       &amp;quot;text&amp;quot;: &amp;quot;Button6&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Display&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
       &amp;quot;Value&amp;quot;: &amp;quot;26&amp;quot;,&lt;br /&gt;
       &amp;quot;Top&amp;quot;: 200,&lt;br /&gt;
       &amp;quot;Left&amp;quot;: 50,&lt;br /&gt;
       &amp;quot;Width&amp;quot;: 100,&lt;br /&gt;
       &amp;quot;Height&amp;quot;: 20&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;Command&amp;quot;: {&lt;br /&gt;
       &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:MyPlugin1&amp;quot;,&lt;br /&gt;
       &amp;quot;Action&amp;quot;: &amp;quot;SetStatus&amp;quot;,&lt;br /&gt;
       &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
           {&lt;br /&gt;
               &amp;quot;Name&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
               &amp;quot;Value&amp;quot;: &amp;quot;26&amp;quot;&lt;br /&gt;
           }&lt;br /&gt;
       ]&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MyDevice1.jpg</id>
		<title>File:MyDevice1.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MyDevice1.jpg"/>
				<updated>2015-03-10T10:29:45Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2015-02-03T15:54:12Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getCommandURL() ==== &lt;br /&gt;
&lt;br /&gt;
- Retrieves command URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: command_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*} getDataRequestURL() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves data request URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: data_request_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceStateVariable(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)(same as api.getDeviceState())&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {Array} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {Array} getListOfSupportedEvents() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of supported events&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Array} - list containing each event a plugin can subscribe to&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getSceneDescription(sceneId, options) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves scene description&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} sceneId - id of the scene&lt;br /&gt;
&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Options can be :&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideTriggers: hides triggers description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideSchedules: hides schedules description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideActions: hides actions description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideNotifications: hides notifications description (default: false)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string}&lt;br /&gt;
&lt;br /&gt;
==== {*} getSendCommandURL() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves send command URL&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getSysinfo() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves sysinfo JSON&lt;br /&gt;
&lt;br /&gt;
- Replaces: sysinfoJson&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== performActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performLuActionOnDevice' Performs an action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== performLuActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performActionOnDevice' Performs a lu_action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceState(deviceId, service, variable, value, options) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable (same as API.setDeviceStateVariable())&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {object} options Optional - a set of options which can be:&lt;br /&gt;
&lt;br /&gt;
- onSuccess: {function} to be called if the call succedes&lt;br /&gt;
&lt;br /&gt;
- onFailure: {function} to be called if the call fails&lt;br /&gt;
&lt;br /&gt;
- context: {object} represents context of execution for onSuccess and onFailure functions&lt;br /&gt;
&lt;br /&gt;
- dynamic: {Boolean} true - state variable will be set in lu_status (default); false - state variable will be set in user_data&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStatePersistent(deviceId, service, variable, value, options) ====&lt;br /&gt;
&lt;br /&gt;
- Sets a persistent state for a device variable using a variableset request (same as API.setDeviceStateVariablePersistent())&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {object} options Optional - a set of options which can be:&lt;br /&gt;
&lt;br /&gt;
- onSuccess: {function} to be called if the call succedes&lt;br /&gt;
&lt;br /&gt;
- onFailure: {function} to be called if the call fails&lt;br /&gt;
&lt;br /&gt;
- context: {object} represents context of execution for onSuccess and onFailure functions&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} options Optional - a set of options which can be:&lt;br /&gt;
&lt;br /&gt;
- onSuccess: {function} to be called if the call succedes&lt;br /&gt;
&lt;br /&gt;
- onFailure: {function} to be called if the call fails&lt;br /&gt;
&lt;br /&gt;
- context: {object} represents context of execution for onSuccess and onFailure functions&lt;br /&gt;
&lt;br /&gt;
- dynamic: {Boolean} true - state variable will be set in lu_status (default); false - state variable will be set in user_data&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariablePersistent(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets a persistent state for a device variable using a variableset request&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} options Optional - a set of options which can be:&lt;br /&gt;
&lt;br /&gt;
- onSuccess: {function} to be called if the call succedes&lt;br /&gt;
&lt;br /&gt;
- onFailure: {function} to be called if the call fails&lt;br /&gt;
&lt;br /&gt;
- context: {object} represents context of execution for onSuccess and onFailure functions&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
=== Migration Walkthrough for plugins with JS ===&lt;br /&gt;
&lt;br /&gt;
With the introduction of our new JavaScript API, plugin mechanism slightly changed. In order to keep a backward compatibility with the UI5 version, there are a couple of thing a developer should do :&lt;br /&gt;
&lt;br /&gt;
* '''Update the JS file using the JavaScript API'''&lt;br /&gt;
&lt;br /&gt;
* '''Update the JSON file with proper calls for JavaScript functions'''&lt;br /&gt;
&lt;br /&gt;
For UI5 version, the JavaScript functions were called in JSON file like this :&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example: Home Care Plugin - JSON file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
		},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For UI7, the JavaScript functions are called like this : &lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File_for_UI7.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Class_Name.Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare_UI7.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;HomeCare.ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By now, you should be asking yourself: &amp;quot;How plugin will work on UI5 if I update these files?&amp;quot;. If you answer by yourself and the answer is : &amp;quot;It won't work&amp;quot;, you are right. For this you will need to do an additional step:&lt;br /&gt;
&lt;br /&gt;
*'''Create different JSON and JS files and perform a check in your Luup code'''&lt;br /&gt;
**As you can see in the above example for JSON file, our choice was to add &amp;quot;''_UI7''&amp;quot; for our JS file : &amp;quot;''J_HomeCare_UI7.js''&amp;quot;. We suggest you to do the same, but this is not a requirement. We did the same with JSON file : &amp;quot;''D_HomeCare_UI7.json''&amp;quot;&lt;br /&gt;
**In order to use the new JSON and JS files in UI7 instead of UI5 versions, &amp;quot;device_json&amp;quot; attribute of your device must set with the JSON file for UI7. For this, you can use the following function:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local function checkVersion()&lt;br /&gt;
	local ui7Check = luup.variable_get(SID, &amp;quot;UI7Check&amp;quot;, lug_device) or &amp;quot;&amp;quot;&lt;br /&gt;
	if ui7Check == &amp;quot;&amp;quot; then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;false&amp;quot;, lug_device)&lt;br /&gt;
		ui7Check = &amp;quot;false&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if( luup.version_branch == 1 and luup.version_major == 7 and ui7Check == &amp;quot;false&amp;quot;) then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;true&amp;quot;, lug_device)&lt;br /&gt;
		luup.attr_set(&amp;quot;device_json&amp;quot;, &amp;quot;Your_UI7_JSON_File&amp;quot;, lug_device)&lt;br /&gt;
		luup.reload()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
''SID'' - your Service ID; ''lug_device'' - your device ID; &lt;br /&gt;
**Call ''checkVersion()'' in your initialization function, before doing something else.&lt;br /&gt;
&lt;br /&gt;
=== HomeCare Plugin - updated for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin as example for what need to be added/updated for UI7. Below you can download plugin files:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;br /&gt;
&lt;br /&gt;
This is the published version of HomeCare plugin that can be downloaded from our appstore. This version is compatible with both UI5 and UI7.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2015-02-03T15:21:50Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getCommandURL() ==== &lt;br /&gt;
&lt;br /&gt;
- Retrieves command URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: command_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*} getDataRequestURL() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves data request URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: data_request_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceStateVariable(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)(same as api.getDeviceState())&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {Array} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {Array} getListOfSupportedEvents() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of supported events&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Array} - list containing each event a plugin can subscribe to&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getSceneDescription(sceneId, options) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves scene description&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} sceneId - id of the scene&lt;br /&gt;
&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Options can be :&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideTriggers: hides triggers description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideSchedules: hides schedules description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideActions: hides actions description (default: false)&lt;br /&gt;
&lt;br /&gt;
{Boolean} hideNotifications: hides notifications description (default: false)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string}&lt;br /&gt;
&lt;br /&gt;
==== {*} getSendCommandURL() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves send command URL&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getSysinfo() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves sysinfo JSON&lt;br /&gt;
&lt;br /&gt;
- Replaces: sysinfoJson&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== performActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performLuActionOnDevice' Performs an action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== performLuActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performActionOnDevice' Performs a lu_action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceState(deviceId, service, variable, value, options) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable (same as API.setDeviceStateVariable())&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {object} context Optional - a set of options which can be:&lt;br /&gt;
&lt;br /&gt;
- onSuccess: {function} to be called if the call succedes&lt;br /&gt;
&lt;br /&gt;
- onFailure: {function} to be called if the call fails&lt;br /&gt;
&lt;br /&gt;
- context: {object} represents context of execution for onSuccess and onFailure functions&lt;br /&gt;
&lt;br /&gt;
- dynamic: {Boolean} true - state variable will be set in lu_status (default); false - state variable will be set in user_data&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
=== Migration Walkthrough for plugins with JS ===&lt;br /&gt;
&lt;br /&gt;
With the introduction of our new JavaScript API, plugin mechanism slightly changed. In order to keep a backward compatibility with the UI5 version, there are a couple of thing a developer should do :&lt;br /&gt;
&lt;br /&gt;
* '''Update the JS file using the JavaScript API'''&lt;br /&gt;
&lt;br /&gt;
* '''Update the JSON file with proper calls for JavaScript functions'''&lt;br /&gt;
&lt;br /&gt;
For UI5 version, the JavaScript functions were called in JSON file like this :&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example: Home Care Plugin - JSON file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
		},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For UI7, the JavaScript functions are called like this : &lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File_for_UI7.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Class_Name.Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare_UI7.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;HomeCare.ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By now, you should be asking yourself: &amp;quot;How plugin will work on UI5 if I update these files?&amp;quot;. If you answer by yourself and the answer is : &amp;quot;It won't work&amp;quot;, you are right. For this you will need to do an additional step:&lt;br /&gt;
&lt;br /&gt;
*'''Create different JSON and JS files and perform a check in your Luup code'''&lt;br /&gt;
**As you can see in the above example for JSON file, our choice was to add &amp;quot;''_UI7''&amp;quot; for our JS file : &amp;quot;''J_HomeCare_UI7.js''&amp;quot;. We suggest you to do the same, but this is not a requirement. We did the same with JSON file : &amp;quot;''D_HomeCare_UI7.json''&amp;quot;&lt;br /&gt;
**In order to use the new JSON and JS files in UI7 instead of UI5 versions, &amp;quot;device_json&amp;quot; attribute of your device must set with the JSON file for UI7. For this, you can use the following function:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local function checkVersion()&lt;br /&gt;
	local ui7Check = luup.variable_get(SID, &amp;quot;UI7Check&amp;quot;, lug_device) or &amp;quot;&amp;quot;&lt;br /&gt;
	if ui7Check == &amp;quot;&amp;quot; then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;false&amp;quot;, lug_device)&lt;br /&gt;
		ui7Check = &amp;quot;false&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if( luup.version_branch == 1 and luup.version_major == 7 and ui7Check == &amp;quot;false&amp;quot;) then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;true&amp;quot;, lug_device)&lt;br /&gt;
		luup.attr_set(&amp;quot;device_json&amp;quot;, &amp;quot;Your_UI7_JSON_File&amp;quot;, lug_device)&lt;br /&gt;
		luup.reload()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
''SID'' - your Service ID; ''lug_device'' - your device ID; &lt;br /&gt;
**Call ''checkVersion()'' in your initialization function, before doing something else.&lt;br /&gt;
&lt;br /&gt;
=== HomeCare Plugin - updated for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin as example for what need to be added/updated for UI7. Below you can download plugin files:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;br /&gt;
&lt;br /&gt;
This is the published version of HomeCare plugin that can be downloaded from our appstore. This version is compatible with both UI5 and UI7.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Devices</id>
		<title>Luup Devices</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Devices"/>
				<updated>2014-12-19T07:49:37Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Sensor - Temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
== Home Automation Device ==&lt;br /&gt;
The generic device type that all MiOS devices implement.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:HaDevice1&lt;br /&gt;
===Variables===&lt;br /&gt;
===Actions===&lt;br /&gt;
== Switch ==&lt;br /&gt;
A binary switch, for an appliance, florescent light, or a relay.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
The state of the device. 1 is on, 0 is off.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the target state of the switch&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue (Integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for on, 0 for off.&lt;br /&gt;
&lt;br /&gt;
== Dimmer ==&lt;br /&gt;
A dimmable light.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:Dimming1&lt;br /&gt;
===Variables===&lt;br /&gt;
newTargetValue: an integer between 0 and 100 indicating the desired % of lighting.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetLoadLevelTarget====&lt;br /&gt;
Sets the desired brightness or load level for the dimming device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newLoadlevelTarget(Integer)&lt;br /&gt;
&lt;br /&gt;
newLoadlevelTarget: an integer between 0 and 100 indicating the desired % of lighting/load.&lt;br /&gt;
&lt;br /&gt;
== Sensor ==&lt;br /&gt;
A security sensor, or any device that can be &amp;quot;tripped&amp;quot;&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:SecuritySensor&lt;br /&gt;
===Variables===&lt;br /&gt;
====Armed====&lt;br /&gt;
An integer. 1 for armed, 0 for disarmed. This is an internal state variable of the MiOS engine and has nothing to do with the state of the sensor.&lt;br /&gt;
====Tripped====&lt;br /&gt;
An integer. 1 for tripped, 0 for not.&lt;br /&gt;
====LastTrip====&lt;br /&gt;
An integer with the UNIX timestamp of the last trip event that the MiOS engine recorded.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetArmed====&lt;br /&gt;
Sets the armed state of the sensor.&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newArmedValue(Integer)&lt;br /&gt;
&lt;br /&gt;
newArmedValue: 1 for armed, 0 for disarmed.&lt;br /&gt;
== HVAC/Climate  ==&lt;br /&gt;
&lt;br /&gt;
=== Service  ===&lt;br /&gt;
&lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_UserOperatingMode1 &lt;br /&gt;
**For action SetModeTarget &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Heat &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Cool &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_FanOperatingMode1 &lt;br /&gt;
**For action SetMode&lt;br /&gt;
&lt;br /&gt;
=== Variables  ===&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_UserOperatingMode1 -- ModeStatus  ====&lt;br /&gt;
&lt;br /&gt;
One of Off, HeatOn, CoolOn, or AutoChangeOver depending on the User operation mode of the thermostat. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_FanOperatingMode1 -- Mode ====&lt;br /&gt;
&lt;br /&gt;
One of Auto, ContinuousOn, or PeriodicOn depending on the fan mode of the thermostat.&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSensor1 -- CurrentTemperature  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the temperature that the thermostat is reporting. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Heat -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the heat setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Cool -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the cool setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
=== Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== SetModeTarget  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired operation mode for the thermostat. &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewModeTarget(String) &lt;br /&gt;
&lt;br /&gt;
NewModeTarget: One of Off, CoolOn, HeatOn, or AutoChangeOver. &lt;br /&gt;
&lt;br /&gt;
==== SetCurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired setpoint. User serviceId urn:upnp-org:serviceId:TemperatureSetpoint1_Heat for heat and urn:upnp-org:serviceId:TemperatureSetpoint1_Cool for cooling &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewCurrentSetpoint(Integer) &lt;br /&gt;
&lt;br /&gt;
NewCurrentSetpoint: An integer value between 0 and 100 specifying the desired heat or cooling setpoint. &lt;br /&gt;
&lt;br /&gt;
==== SetMode  ====&lt;br /&gt;
&lt;br /&gt;
Sets the fan operation mode for the thermostat &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewMode(String) &lt;br /&gt;
&lt;br /&gt;
NewMode: One of ContinuousOn or Auto, depending on the desired mode of operation for the HVAC system's fan. &lt;br /&gt;
&lt;br /&gt;
=== Examples  ===&lt;br /&gt;
&lt;br /&gt;
Set Thermostat #4 to Cool:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=4&amp;amp;amp;serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;amp;amp;action=SetModeTarget&amp;amp;amp;NewModeTarget=CoolOn &lt;br /&gt;
&lt;br /&gt;
Set Thermostat #98 cool setpoint to 70:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=98&amp;amp;amp;serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&amp;amp;amp;action=SetCurrentSetpoint&amp;amp;amp;NewCurrentSetpoint=70&lt;br /&gt;
&lt;br /&gt;
== Lock ==&lt;br /&gt;
Lorem ipsum dolor sit amet, ultricies ligula ligula maecenas, sed laboriosam erat.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:DoorLock1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
1 for locked, 0 for unlocked&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the desired lock state of the door lock&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue(integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for lock, 0 for unlock&lt;br /&gt;
== Window Covering ==&lt;br /&gt;
Blinds and shades.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:WindowCovering1&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
**Supports the same actions and variables as a switch. On is closed, Off is open.&lt;br /&gt;
===Actions===&lt;br /&gt;
====Up====&lt;br /&gt;
Moves the covering up.&lt;br /&gt;
====Down====&lt;br /&gt;
Moves the covering down.&lt;br /&gt;
====Stop====&lt;br /&gt;
Stops the covering moving.&lt;br /&gt;
== Sensor - Humidity ==&lt;br /&gt;
A humidity sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:HumiditySensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current humidity level that the sensor is reporting.&lt;br /&gt;
== Sensor - Temperature ==&lt;br /&gt;
A temperature sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:upnp-org:serviceId:TemperatureSensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentTemperature(Integer): The current temperature in degrees the sensor is reporting.&lt;br /&gt;
&lt;br /&gt;
== Sensor - Light ==&lt;br /&gt;
A light sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:schemas-micasaverde-com:service:LightSensor:1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current light level that the sensor is reporting.&lt;br /&gt;
&lt;br /&gt;
== Power Meter ==&lt;br /&gt;
A power meter or a device that can display power usage.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:EnergyMetering1&lt;br /&gt;
===Variables===&lt;br /&gt;
Watts(Integer): The energy draw the meter is recording, in watts.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Devices</id>
		<title>Luup Devices</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Devices"/>
				<updated>2014-12-19T07:49:20Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Sensor - Light */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
== Home Automation Device ==&lt;br /&gt;
The generic device type that all MiOS devices implement.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:HaDevice1&lt;br /&gt;
===Variables===&lt;br /&gt;
===Actions===&lt;br /&gt;
== Switch ==&lt;br /&gt;
A binary switch, for an appliance, florescent light, or a relay.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
The state of the device. 1 is on, 0 is off.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the target state of the switch&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue (Integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for on, 0 for off.&lt;br /&gt;
&lt;br /&gt;
== Dimmer ==&lt;br /&gt;
A dimmable light.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:Dimming1&lt;br /&gt;
===Variables===&lt;br /&gt;
newTargetValue: an integer between 0 and 100 indicating the desired % of lighting.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetLoadLevelTarget====&lt;br /&gt;
Sets the desired brightness or load level for the dimming device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newLoadlevelTarget(Integer)&lt;br /&gt;
&lt;br /&gt;
newLoadlevelTarget: an integer between 0 and 100 indicating the desired % of lighting/load.&lt;br /&gt;
&lt;br /&gt;
== Sensor ==&lt;br /&gt;
A security sensor, or any device that can be &amp;quot;tripped&amp;quot;&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:SecuritySensor&lt;br /&gt;
===Variables===&lt;br /&gt;
====Armed====&lt;br /&gt;
An integer. 1 for armed, 0 for disarmed. This is an internal state variable of the MiOS engine and has nothing to do with the state of the sensor.&lt;br /&gt;
====Tripped====&lt;br /&gt;
An integer. 1 for tripped, 0 for not.&lt;br /&gt;
====LastTrip====&lt;br /&gt;
An integer with the UNIX timestamp of the last trip event that the MiOS engine recorded.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetArmed====&lt;br /&gt;
Sets the armed state of the sensor.&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newArmedValue(Integer)&lt;br /&gt;
&lt;br /&gt;
newArmedValue: 1 for armed, 0 for disarmed.&lt;br /&gt;
== HVAC/Climate  ==&lt;br /&gt;
&lt;br /&gt;
=== Service  ===&lt;br /&gt;
&lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_UserOperatingMode1 &lt;br /&gt;
**For action SetModeTarget &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Heat &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Cool &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_FanOperatingMode1 &lt;br /&gt;
**For action SetMode&lt;br /&gt;
&lt;br /&gt;
=== Variables  ===&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_UserOperatingMode1 -- ModeStatus  ====&lt;br /&gt;
&lt;br /&gt;
One of Off, HeatOn, CoolOn, or AutoChangeOver depending on the User operation mode of the thermostat. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_FanOperatingMode1 -- Mode ====&lt;br /&gt;
&lt;br /&gt;
One of Auto, ContinuousOn, or PeriodicOn depending on the fan mode of the thermostat.&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSensor1 -- CurrentTemperature  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the temperature that the thermostat is reporting. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Heat -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the heat setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Cool -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the cool setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
=== Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== SetModeTarget  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired operation mode for the thermostat. &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewModeTarget(String) &lt;br /&gt;
&lt;br /&gt;
NewModeTarget: One of Off, CoolOn, HeatOn, or AutoChangeOver. &lt;br /&gt;
&lt;br /&gt;
==== SetCurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired setpoint. User serviceId urn:upnp-org:serviceId:TemperatureSetpoint1_Heat for heat and urn:upnp-org:serviceId:TemperatureSetpoint1_Cool for cooling &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewCurrentSetpoint(Integer) &lt;br /&gt;
&lt;br /&gt;
NewCurrentSetpoint: An integer value between 0 and 100 specifying the desired heat or cooling setpoint. &lt;br /&gt;
&lt;br /&gt;
==== SetMode  ====&lt;br /&gt;
&lt;br /&gt;
Sets the fan operation mode for the thermostat &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewMode(String) &lt;br /&gt;
&lt;br /&gt;
NewMode: One of ContinuousOn or Auto, depending on the desired mode of operation for the HVAC system's fan. &lt;br /&gt;
&lt;br /&gt;
=== Examples  ===&lt;br /&gt;
&lt;br /&gt;
Set Thermostat #4 to Cool:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=4&amp;amp;amp;serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;amp;amp;action=SetModeTarget&amp;amp;amp;NewModeTarget=CoolOn &lt;br /&gt;
&lt;br /&gt;
Set Thermostat #98 cool setpoint to 70:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=98&amp;amp;amp;serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&amp;amp;amp;action=SetCurrentSetpoint&amp;amp;amp;NewCurrentSetpoint=70&lt;br /&gt;
&lt;br /&gt;
== Lock ==&lt;br /&gt;
Lorem ipsum dolor sit amet, ultricies ligula ligula maecenas, sed laboriosam erat.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:DoorLock1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
1 for locked, 0 for unlocked&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the desired lock state of the door lock&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue(integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for lock, 0 for unlock&lt;br /&gt;
== Window Covering ==&lt;br /&gt;
Blinds and shades.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:WindowCovering1&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
**Supports the same actions and variables as a switch. On is closed, Off is open.&lt;br /&gt;
===Actions===&lt;br /&gt;
====Up====&lt;br /&gt;
Moves the covering up.&lt;br /&gt;
====Down====&lt;br /&gt;
Moves the covering down.&lt;br /&gt;
====Stop====&lt;br /&gt;
Stops the covering moving.&lt;br /&gt;
== Sensor - Humidity ==&lt;br /&gt;
A humidity sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:HumiditySensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current humidity level that the sensor is reporting.&lt;br /&gt;
== Sensor - Temperature ==&lt;br /&gt;
A temperature sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:upnp-org:serviceId:TemperatureSensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current temperature in degrees the sensor is reporting.&lt;br /&gt;
== Sensor - Light ==&lt;br /&gt;
A light sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:schemas-micasaverde-com:service:LightSensor:1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current light level that the sensor is reporting.&lt;br /&gt;
&lt;br /&gt;
== Power Meter ==&lt;br /&gt;
A power meter or a device that can display power usage.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:EnergyMetering1&lt;br /&gt;
===Variables===&lt;br /&gt;
Watts(Integer): The energy draw the meter is recording, in watts.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_Devices</id>
		<title>Luup Devices</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_Devices"/>
				<updated>2014-12-19T07:47:24Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Sensor - Light */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
== Home Automation Device ==&lt;br /&gt;
The generic device type that all MiOS devices implement.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:HaDevice1&lt;br /&gt;
===Variables===&lt;br /&gt;
===Actions===&lt;br /&gt;
== Switch ==&lt;br /&gt;
A binary switch, for an appliance, florescent light, or a relay.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
The state of the device. 1 is on, 0 is off.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the target state of the switch&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue (Integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for on, 0 for off.&lt;br /&gt;
&lt;br /&gt;
== Dimmer ==&lt;br /&gt;
A dimmable light.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:Dimming1&lt;br /&gt;
===Variables===&lt;br /&gt;
newTargetValue: an integer between 0 and 100 indicating the desired % of lighting.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetLoadLevelTarget====&lt;br /&gt;
Sets the desired brightness or load level for the dimming device.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newLoadlevelTarget(Integer)&lt;br /&gt;
&lt;br /&gt;
newLoadlevelTarget: an integer between 0 and 100 indicating the desired % of lighting/load.&lt;br /&gt;
&lt;br /&gt;
== Sensor ==&lt;br /&gt;
A security sensor, or any device that can be &amp;quot;tripped&amp;quot;&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:micasaverde-com:serviceId:SecuritySensor&lt;br /&gt;
===Variables===&lt;br /&gt;
====Armed====&lt;br /&gt;
An integer. 1 for armed, 0 for disarmed. This is an internal state variable of the MiOS engine and has nothing to do with the state of the sensor.&lt;br /&gt;
====Tripped====&lt;br /&gt;
An integer. 1 for tripped, 0 for not.&lt;br /&gt;
====LastTrip====&lt;br /&gt;
An integer with the UNIX timestamp of the last trip event that the MiOS engine recorded.&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetArmed====&lt;br /&gt;
Sets the armed state of the sensor.&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newArmedValue(Integer)&lt;br /&gt;
&lt;br /&gt;
newArmedValue: 1 for armed, 0 for disarmed.&lt;br /&gt;
== HVAC/Climate  ==&lt;br /&gt;
&lt;br /&gt;
=== Service  ===&lt;br /&gt;
&lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_UserOperatingMode1 &lt;br /&gt;
**For action SetModeTarget &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Heat &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:TemperatureSetpoint1_Cool &lt;br /&gt;
**For action NewCurrentSetpoint &lt;br /&gt;
*urn:upnp-org:serviceId:HVAC_FanOperatingMode1 &lt;br /&gt;
**For action SetMode&lt;br /&gt;
&lt;br /&gt;
=== Variables  ===&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_UserOperatingMode1 -- ModeStatus  ====&lt;br /&gt;
&lt;br /&gt;
One of Off, HeatOn, CoolOn, or AutoChangeOver depending on the User operation mode of the thermostat. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:HVAC_FanOperatingMode1 -- Mode ====&lt;br /&gt;
&lt;br /&gt;
One of Auto, ContinuousOn, or PeriodicOn depending on the fan mode of the thermostat.&lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSensor1 -- CurrentTemperature  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the temperature that the thermostat is reporting. &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Heat -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the heat setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
==== urn:upnp-org:serviceId:TemperatureSetpoint1_Cool -- CurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
An integer value representing the cool setpoint for the thermostat &lt;br /&gt;
&lt;br /&gt;
=== Actions  ===&lt;br /&gt;
&lt;br /&gt;
==== SetModeTarget  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired operation mode for the thermostat. &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewModeTarget(String) &lt;br /&gt;
&lt;br /&gt;
NewModeTarget: One of Off, CoolOn, HeatOn, or AutoChangeOver. &lt;br /&gt;
&lt;br /&gt;
==== SetCurrentSetpoint  ====&lt;br /&gt;
&lt;br /&gt;
Sets the desired setpoint. User serviceId urn:upnp-org:serviceId:TemperatureSetpoint1_Heat for heat and urn:upnp-org:serviceId:TemperatureSetpoint1_Cool for cooling &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewCurrentSetpoint(Integer) &lt;br /&gt;
&lt;br /&gt;
NewCurrentSetpoint: An integer value between 0 and 100 specifying the desired heat or cooling setpoint. &lt;br /&gt;
&lt;br /&gt;
==== SetMode  ====&lt;br /&gt;
&lt;br /&gt;
Sets the fan operation mode for the thermostat &lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' NewMode(String) &lt;br /&gt;
&lt;br /&gt;
NewMode: One of ContinuousOn or Auto, depending on the desired mode of operation for the HVAC system's fan. &lt;br /&gt;
&lt;br /&gt;
=== Examples  ===&lt;br /&gt;
&lt;br /&gt;
Set Thermostat #4 to Cool:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=4&amp;amp;amp;serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&amp;amp;amp;action=SetModeTarget&amp;amp;amp;NewModeTarget=CoolOn &lt;br /&gt;
&lt;br /&gt;
Set Thermostat #98 cool setpoint to 70:   veraIP:3480/data_request?id=lu_action&amp;amp;amp;DeviceNum=98&amp;amp;amp;serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Cool&amp;amp;amp;action=SetCurrentSetpoint&amp;amp;amp;NewCurrentSetpoint=70&lt;br /&gt;
&lt;br /&gt;
== Lock ==&lt;br /&gt;
Lorem ipsum dolor sit amet, ultricies ligula ligula maecenas, sed laboriosam erat.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:DoorLock1&lt;br /&gt;
===Variables===&lt;br /&gt;
====Status====&lt;br /&gt;
1 for locked, 0 for unlocked&lt;br /&gt;
===Actions===&lt;br /&gt;
====SetTarget====&lt;br /&gt;
Sets the desired lock state of the door lock&lt;br /&gt;
&lt;br /&gt;
'''Arguments:''' newTargetValue(integer)&lt;br /&gt;
&lt;br /&gt;
newTargetValue: 1 for lock, 0 for unlock&lt;br /&gt;
== Window Covering ==&lt;br /&gt;
Blinds and shades.&lt;br /&gt;
===Service===&lt;br /&gt;
*urn:upnp-org:serviceId:WindowCovering1&lt;br /&gt;
*urn:upnp-org:serviceId:SwitchPower1&lt;br /&gt;
**Supports the same actions and variables as a switch. On is closed, Off is open.&lt;br /&gt;
===Actions===&lt;br /&gt;
====Up====&lt;br /&gt;
Moves the covering up.&lt;br /&gt;
====Down====&lt;br /&gt;
Moves the covering down.&lt;br /&gt;
====Stop====&lt;br /&gt;
Stops the covering moving.&lt;br /&gt;
== Sensor - Humidity ==&lt;br /&gt;
A humidity sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:HumiditySensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current humidity level that the sensor is reporting.&lt;br /&gt;
== Sensor - Temperature ==&lt;br /&gt;
A temperature sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:upnp-org:serviceId:TemperatureSensor1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentLevel(Integer): The current temperature in degrees the sensor is reporting.&lt;br /&gt;
== Sensor - Light ==&lt;br /&gt;
A light sensor.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:schemas-micasaverde-com:service:LightSensor:1&lt;br /&gt;
===Variables===&lt;br /&gt;
CurrentTemperature(Integer): The current light level that the sensor is reporting.&lt;br /&gt;
&lt;br /&gt;
== Power Meter ==&lt;br /&gt;
A power meter or a device that can display power usage.&lt;br /&gt;
===Service===&lt;br /&gt;
urn:micasaverde-com:serviceId:EnergyMetering1&lt;br /&gt;
===Variables===&lt;br /&gt;
Watts(Integer): The energy draw the meter is recording, in watts.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-11-19T16:06:42Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getCommandURL() ==== &lt;br /&gt;
&lt;br /&gt;
- Retrieves command URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: command_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*} getDataRequestURL() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves data request URL&lt;br /&gt;
&lt;br /&gt;
- Replaces: data_request_url&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {Array} getListOfSupportedEvents() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of supported events&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Array} - list containing each event a plugin can subscribe to&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getSysinfo() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves sysinfo JSON&lt;br /&gt;
&lt;br /&gt;
- Replaces: sysinfoJson&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== performActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performLuActionOnDevice' Performs an action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== performLuActionOnDevice(deviceId, service, action, options) ====&lt;br /&gt;
&lt;br /&gt;
- Same as 'performActionOnDevice' Performs a lu_action on a device&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId&lt;br /&gt;
* {string} service&lt;br /&gt;
* {string} action&lt;br /&gt;
* {object} options Optional&lt;br /&gt;
&lt;br /&gt;
- Ex: options can be: { actionArguments: {arg1: 'val1', arg2: 'val2'}, onSuccess: function() {}, onFailure: function() {}, context: that }&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
=== Migration Walkthrough for plugins with JS ===&lt;br /&gt;
&lt;br /&gt;
With the introduction of our new JavaScript API, plugin mechanism slightly changed. In order to keep a backward compatibility with the UI5 version, there are a couple of thing a developer should do :&lt;br /&gt;
&lt;br /&gt;
* '''Update the JS file using the JavaScript API'''&lt;br /&gt;
&lt;br /&gt;
* '''Update the JSON file with proper calls for JavaScript functions'''&lt;br /&gt;
&lt;br /&gt;
For UI5 version, the JavaScript functions were called in JSON file like this :&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example: Home Care Plugin - JSON file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
		},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For UI7, the JavaScript functions are called like this : &lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File_for_UI7.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Class_Name.Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare_UI7.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;HomeCare.ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By now, you should be asking yourself: &amp;quot;How plugin will work on UI5 if I update these files?&amp;quot;. If you answer by yourself and the answer is : &amp;quot;It won't work&amp;quot;, you are right. For this you will need to do an additional step:&lt;br /&gt;
&lt;br /&gt;
*'''Create different JSON and JS files and perform a check in your Luup code'''&lt;br /&gt;
**As you can see in the above example for JSON file, our choice was to add &amp;quot;''_UI7''&amp;quot; for our JS file : &amp;quot;''J_HomeCare_UI7.js''&amp;quot;. We suggest you to do the same, but this is not a requirement. We did the same with JSON file : &amp;quot;''D_HomeCare_UI7.json''&amp;quot;&lt;br /&gt;
**In order to use the new JSON and JS files in UI7 instead of UI5 versions, &amp;quot;device_json&amp;quot; attribute of your device must set with the JSON file for UI7. For this, you can use the following function:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local function checkVersion()&lt;br /&gt;
	local ui7Check = luup.variable_get(SID, &amp;quot;UI7Check&amp;quot;, lug_device) or &amp;quot;&amp;quot;&lt;br /&gt;
	if ui7Check == &amp;quot;&amp;quot; then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;false&amp;quot;, lug_device)&lt;br /&gt;
		ui7Check = &amp;quot;false&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if( luup.version_branch == 1 and luup.version_major == 7 and ui7Check == &amp;quot;false&amp;quot;) then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;true&amp;quot;, lug_device)&lt;br /&gt;
		luup.attr_set(&amp;quot;device_json&amp;quot;, &amp;quot;Your_UI7_JSON_File&amp;quot;, lug_device)&lt;br /&gt;
		luup.reload()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
''SID'' - your Service ID; ''lug_device'' - your device ID; &lt;br /&gt;
**Call ''checkVersion()'' in your initialization function, before doing something else.&lt;br /&gt;
&lt;br /&gt;
=== HomeCare Plugin - updated for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin as example for what need to be added/updated for UI7. Below you can download plugin files:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;br /&gt;
&lt;br /&gt;
This is the published version of HomeCare plugin that can be downloaded from our appstore. This version is compatible with both UI5 and UI7.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-11-03T07:19:08Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Get “Mode” variable value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==“Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Get “Mode” variable value ===&lt;br /&gt;
http://IP:3480/data_request?id=variableget&amp;amp;Variable=Mode&lt;br /&gt;
&lt;br /&gt;
=== Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-11-03T07:17:41Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Get “Mode” variable value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==“Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Get “Mode” variable value ===&lt;br /&gt;
http://GATEWAY_IP:3480/data_request?id=variableget&amp;amp;Variable=Mode&lt;br /&gt;
&lt;br /&gt;
=== Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-11-03T07:11:41Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Get “Mode” variable value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==“Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Get “Mode” variable value ===&lt;br /&gt;
http://GATEWAY_IP:3480/data_request?id=variableget&amp;amp;Variable=Mode&lt;br /&gt;
&lt;br /&gt;
http://GATEWAY_IP:3480/data_request?id=variableget&amp;amp;DeviceNum=0&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;Variable=Mode&lt;br /&gt;
&lt;br /&gt;
=== Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-11-03T07:08:18Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: /* Get “Mode” variable value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==“Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Get “Mode” variable value ===&lt;br /&gt;
http://GATEWAY_IP:3480/data_request?id=variableget&amp;amp;DeviceNum=0&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;Variable=Mode&lt;br /&gt;
&lt;br /&gt;
=== Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-10T13:38:36Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
=== Migration Walkthrough for plugins with JS ===&lt;br /&gt;
&lt;br /&gt;
With the introduction of our new JavaScript API, plugin mechanism slightly changed. In order to keep a backward compatibility with the UI5 version, there are a couple of thing a developer should do :&lt;br /&gt;
&lt;br /&gt;
* '''Update the JS file using the JavaScript API'''&lt;br /&gt;
&lt;br /&gt;
* '''Update the JSON file with proper calls for JavaScript functions'''&lt;br /&gt;
&lt;br /&gt;
For UI5 version, the JavaScript functions were called in JSON file like this :&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example: Home Care Plugin - JSON file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
		},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For UI7, the JavaScript functions are called like this : &lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;ScriptName&amp;quot;: &amp;quot;Your_JS_File_for_UI7.js&amp;quot;,'''&lt;br /&gt;
&lt;br /&gt;
'''&amp;quot;Function&amp;quot;: &amp;quot;Your_Class_Name.Your_Function_Name&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;Label&amp;quot;: {&lt;br /&gt;
		&amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
		&amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
	&amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
	&amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
	&amp;quot;ScriptName&amp;quot;: &amp;quot;J_HomeCare_UI7.js&amp;quot;,&lt;br /&gt;
	&amp;quot;Function&amp;quot;: &amp;quot;HomeCare.ShowUsers&amp;quot;&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By now, you should be asking yourself: &amp;quot;How plugin will work on UI5 if I update these files?&amp;quot;. If you answer by yourself and the answer is : &amp;quot;It won't work&amp;quot;, you are right. For this you will need to do an additional step:&lt;br /&gt;
&lt;br /&gt;
*'''Create different JSON and JS files and perform a check in your Luup code'''&lt;br /&gt;
**As you can see in the above example for JSON file, our choice was to add &amp;quot;''_UI7''&amp;quot; for our JS file : &amp;quot;''J_HomeCare_UI7.js''&amp;quot;. We suggest you to do the same, but this is not a requirement. We did the same with JSON file : &amp;quot;''D_HomeCare_UI7.json''&amp;quot;&lt;br /&gt;
**In order to use the new JSON and JS files in UI7 instead of UI5 versions, &amp;quot;device_json&amp;quot; attribute of your device must set with the JSON file for UI7. For this, you can use the following function:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local function checkVersion()&lt;br /&gt;
	local ui7Check = luup.variable_get(SID, &amp;quot;UI7Check&amp;quot;, lug_device) or &amp;quot;&amp;quot;&lt;br /&gt;
	if ui7Check == &amp;quot;&amp;quot; then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;false&amp;quot;, lug_device)&lt;br /&gt;
		ui7Check = &amp;quot;false&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if( luup.version_branch == 1 and luup.version_major == 7 and ui7Check == &amp;quot;false&amp;quot;) then&lt;br /&gt;
		luup.variable_set(SID, &amp;quot;UI7Check&amp;quot;, &amp;quot;true&amp;quot;, lug_device)&lt;br /&gt;
		luup.attr_set(&amp;quot;device_json&amp;quot;, &amp;quot;Your_UI7_JSON_File&amp;quot;, lug_device)&lt;br /&gt;
		luup.reload()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
''SID'' - your Service ID; ''lug_device'' - your device ID; &lt;br /&gt;
**Call ''checkVersion()'' in your initialization function, before doing something else.&lt;br /&gt;
&lt;br /&gt;
=== HomeCare Plugin - updated for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin as example for what need to be added/updated for UI7. Below you can download plugin files:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;br /&gt;
&lt;br /&gt;
This is the published version of HomeCare plugin that can be downloaded from our appstore. This version is compatible with both UI5 and UI7.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:HomeCare.zip</id>
		<title>File:HomeCare.zip</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:HomeCare.zip"/>
				<updated>2014-10-10T12:42:33Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: Andreimios uploaded a new version of &amp;amp;quot;File:HomeCare.zip&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-10T11:17:30Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== HomeCare Plugin - updated for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin as example for what need to be added/updated for UI7. Below you can download plugin files:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;br /&gt;
&lt;br /&gt;
This is the published version of HomeCare plugin that can be downloaded from our appstore. This version is compatible with both UI5 and UI7.&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:HomeCare.zip</id>
		<title>File:HomeCare.zip</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:HomeCare.zip"/>
				<updated>2014-10-10T11:08:43Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: Andreimios uploaded a new version of &amp;amp;quot;File:HomeCare.zip&amp;amp;quot;: - added all HomeCare Plugin files&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-06T12:22:45Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Example files for UI7 ===&lt;br /&gt;
&lt;br /&gt;
We use the HomeCare plugin for example. Below you can download the JSON and JavaScript files for both UI5 and UI7:&lt;br /&gt;
&lt;br /&gt;
[[File:HomeCare.zip]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:HomeCare.zip</id>
		<title>File:HomeCare.zip</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:HomeCare.zip"/>
				<updated>2014-10-06T12:21:23Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-06T08:54:42Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-06T08:53:10Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;br /&gt;
&lt;br /&gt;
* on_startup_showModalLoading&lt;br /&gt;
** triggered before loading resources in the browser&lt;br /&gt;
*on_startup_luStatusLoaded&lt;br /&gt;
** triggered after luStatus was successfully parsed&lt;br /&gt;
** parameter: luStatusObject&lt;br /&gt;
* on_startup_show2gInterface&lt;br /&gt;
** triggered after requesting account devices only if UI is not in ‘local mode’ and ‘slowConnection’ flag is set&lt;br /&gt;
* on_ui_requireSave&lt;br /&gt;
** triggered if user data was changed and save wasn’t issued&lt;br /&gt;
* on_ui_userDataFirstLoaded&lt;br /&gt;
** fired if user data was loaded for the first time&lt;br /&gt;
* on_ui_staticDataAdded&lt;br /&gt;
** fired if static_data was added to user data&lt;br /&gt;
** parameter: staticDataObject&lt;br /&gt;
* on_ui_staticDataChanged&lt;br /&gt;
** fired if static_data was changed after parsing user data&lt;br /&gt;
** parameter: changedStaticDataObject&lt;br /&gt;
* on_ui_staticDataRemoved&lt;br /&gt;
** fired if static_data was removed after parsing user data&lt;br /&gt;
** parameter: idForRemovedStaticDataObject&lt;br /&gt;
* on_ui_setupDeviceAdded&lt;br /&gt;
** fired if new setup device (menu item) is added&lt;br /&gt;
** parameter: setupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceChanged&lt;br /&gt;
** fired if setup device (menu item) is changed&lt;br /&gt;
** parameter: changedSetupDeviceObject&lt;br /&gt;
* on_ui_setupDeviceRemoved&lt;br /&gt;
** fired if setup device (menu item) is removed&lt;br /&gt;
** parameter: idForRemovedSetupDeviceObject&lt;br /&gt;
* on_ui_sectionAdded&lt;br /&gt;
** triggered when new section is added&lt;br /&gt;
** parameter: sectionObject&lt;br /&gt;
* on_ui_sectionChanged&lt;br /&gt;
** fired after section was changed&lt;br /&gt;
** parameter: changedSectionObject&lt;br /&gt;
* on_ui_sectionRemoved&lt;br /&gt;
** fired after section was removed&lt;br /&gt;
** parameter: idForRemovedSectionObject&lt;br /&gt;
* on_ui_roomAdded&lt;br /&gt;
** fired when new room was added to user data&lt;br /&gt;
** parameter: roomObject&lt;br /&gt;
* on_ui_roomChanged&lt;br /&gt;
** fired after room was changed&lt;br /&gt;
** parameter: changedRoomObject&lt;br /&gt;
* on_ui_roomRemoved&lt;br /&gt;
** fired after room was removed from user data&lt;br /&gt;
** parameter: idForRemovedRoomObject&lt;br /&gt;
* on_ui_deviceAdded&lt;br /&gt;
** fired after device was added to user data&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceChanged&lt;br /&gt;
** fired after device was found changed in user data&lt;br /&gt;
** parameter: changedDeviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_deviceRemoved&lt;br /&gt;
** fired after device was found removed from user data&lt;br /&gt;
** parameter: idForRemovedDeviceObject&lt;br /&gt;
* on_ui_deviceJobsReceived&lt;br /&gt;
** fired when jobs are found for a device in lu_status&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_sceneAdded&lt;br /&gt;
** fired after scene was added&lt;br /&gt;
** parameter: sceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired after scene was changed&lt;br /&gt;
** parameter: changedSceneObject&lt;br /&gt;
* on_ui_sceneChanged&lt;br /&gt;
** fired when scene is removed&lt;br /&gt;
** parameter: idForRemovedSceneObject&lt;br /&gt;
* on_ui_pluginAdded&lt;br /&gt;
** triggered when plugin is added to user data&lt;br /&gt;
** parameter: pluginObject&lt;br /&gt;
* on_ui_pluginChanged&lt;br /&gt;
** triggered when plugin is changed&lt;br /&gt;
** parameter: changedPluginObject&lt;br /&gt;
* on_ui_pluginRemoved&lt;br /&gt;
** triggered when plugin is removed&lt;br /&gt;
** parameter: idForRemovedPluginObject&lt;br /&gt;
* on_ui_extraSubmenuItemAdded&lt;br /&gt;
** triggered when extra submenu item is added&lt;br /&gt;
** parameter: extraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** submenuItem: object containing submenu item&lt;br /&gt;
**** deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemChanged&lt;br /&gt;
** triggered when extra submenu item is changed&lt;br /&gt;
** parameter: changedExtraSubmenuItemObject&lt;br /&gt;
*** wrapper for:&lt;br /&gt;
**** oldObj: contains previous submenu item&lt;br /&gt;
**** newObj: wrapper for:&lt;br /&gt;
*****  submenuItem: object containing submenu item&lt;br /&gt;
*****  deviceType: string which contains the type of device for which the submenu item is added&lt;br /&gt;
* on_ui_extraSubmenuItemRemoved:&lt;br /&gt;
** triggered when an extra submenu item is removed&lt;br /&gt;
** parameter: idForRemovedExtraSubmenuItemObject&lt;br /&gt;
* on_ui_cardAdded&lt;br /&gt;
** triggered when card is added to user data&lt;br /&gt;
** parameter: cardObject&lt;br /&gt;
* on_ui_cardChanged&lt;br /&gt;
** triggered when card is found changed in user data&lt;br /&gt;
** parameter: changedCardObject&lt;br /&gt;
* on_ui_cardRemoved&lt;br /&gt;
** triggered when card is removed from user data&lt;br /&gt;
** parameter: idForRemovedCardObject&lt;br /&gt;
* on_ui_jobsUpdated&lt;br /&gt;
** triggered when job is updated in lu_status&lt;br /&gt;
** parameter: luStatusJobsObject&lt;br /&gt;
* on_ui_deviceStatusChanged&lt;br /&gt;
** triggered when device status is changed&lt;br /&gt;
** parameter: deviceObjectFromLuStatus&lt;br /&gt;
* on_ui_syncClock&lt;br /&gt;
** triggered after lu_status is parsed&lt;br /&gt;
** parameter: luStatusLocalTime&lt;br /&gt;
* on_ui_initFinished&lt;br /&gt;
** fired when init has finished (UI should be ready now)&lt;br /&gt;
* on_ui_setUserAuthenticated&lt;br /&gt;
** fired after login is successful&lt;br /&gt;
* on_ui_saveFinished&lt;br /&gt;
** fired after save is finished&lt;br /&gt;
* on_ui_initNotLogged&lt;br /&gt;
** triggered if user is not logged in&lt;br /&gt;
* on_ui_alertsUpdated&lt;br /&gt;
** fired after alert list was updated&lt;br /&gt;
* on_ui_refreshDashboardCards&lt;br /&gt;
** triggered when dashboard cards are refreshed&lt;br /&gt;
* on_ui_engineAvailable&lt;br /&gt;
** triggered if engine is not busy&lt;br /&gt;
* on_ui_2GEnabled&lt;br /&gt;
** triggered when parsing lu_status if 2G is enabled&lt;br /&gt;
* on_ui_userDataSetTemperatureFormat&lt;br /&gt;
** triggered after temperature format is set in user data&lt;br /&gt;
** parameter: userDataObject&lt;br /&gt;
* on_ui_userDataLoaded&lt;br /&gt;
** triggered after user data parsing is completed&lt;br /&gt;
* on_parseUserData&lt;br /&gt;
** triggered when user data parsing is started&lt;br /&gt;
* on_ui_accountUnitsLoaded&lt;br /&gt;
** fired after account lis from MMS was successfully loaded&lt;br /&gt;
* accountInformationLoaded&lt;br /&gt;
** triggered after account information is loaded&lt;br /&gt;
** parameter: accountInfoObject&lt;br /&gt;
* on_ui_finishDrawingMenu&lt;br /&gt;
** triggered after parsing of user data setup devices has finished&lt;br /&gt;
* on_ui_deviceTypeChanged&lt;br /&gt;
** triggered if device type for a device has changed&lt;br /&gt;
** parameter: deviceObject&lt;br /&gt;
*** wrapper object for&lt;br /&gt;
**** device: this is the actual object representing the device&lt;br /&gt;
**** deviceTemplate: object with the static data associated to this device type&lt;br /&gt;
* on_ui_hideModalLoading&lt;br /&gt;
** triggered each time a time consuming job finishes (so that UI can hide modal loading)&lt;br /&gt;
* on_ui_showUserDataSaveFailure&lt;br /&gt;
** triggered if user data save has failed&lt;br /&gt;
* on_ui_showErrorMessage&lt;br /&gt;
** fired if application has error message to send to the UI&lt;br /&gt;
* on_ui_cpanel_before_close&lt;br /&gt;
** fired before closing the cpanel to allow plugins to cleanup their data&lt;br /&gt;
** parameters: idForDeviceWhichOpenedTheCpanel&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-06T08:42:09Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-06T08:41:41Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
The list of available events can be obtained with the following command:&lt;br /&gt;
&lt;br /&gt;
'''api.getListOfSupportedEvents()'''&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Alerts</id>
		<title>Alerts</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Alerts"/>
				<updated>2014-10-02T14:13:31Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
3rd party developers can now use the alert system in plugins. They can generate different alert types with or without user notification. Alert messages generated by a device can be seen in '''&amp;quot;Logs&amp;quot;''' tab for that device.&lt;br /&gt;
&lt;br /&gt;
[[File:logs_button.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
Let's take as example the HomeCare plugin. Users should be notify when a sensor has not been tripped for a specified amount of time. Here is how &amp;quot;Alerts&amp;quot; page for HomeCare plugin looks like:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you can see the '''source''' of this notification is our HomeCare plugin, '''type''' for it is &amp;quot;user created trigger&amp;quot; and '''desctiption''' is the one we added in plugin.&lt;br /&gt;
&lt;br /&gt;
And here is the detailed message for this notification:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification_alert.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
== Alert HTTP Request ==&lt;br /&gt;
&lt;br /&gt;
http://IP:3480/data_request?id=add_alert&amp;amp;device=DEVICE_ID&amp;amp;type=3&amp;amp;source=3&amp;amp;description=ALERT_DESCRIPTION&amp;amp;users=USERS_LIST&lt;br /&gt;
&lt;br /&gt;
* DEVICE_ID - device # that generates the alert;&lt;br /&gt;
* ALERT_TYPE - should be 3, DO NOT CHANGE;&lt;br /&gt;
* ALERT_SOURCE - should be 3, DO NOT CHANGE;&lt;br /&gt;
* ALERT_DESCRIPTION - URL encoded message used as description for the alert;&lt;br /&gt;
* USERS_LIST - a list with user ID separated by commas that should be notify[left blank if no user notification is required].&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Alerts</id>
		<title>Alerts</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Alerts"/>
				<updated>2014-10-02T14:10:22Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
3rd party developers can now use the alert system in plugins. They can generate different alert types with or without user notification. Alert messages generated by a device can be seen in '''&amp;quot;Logs&amp;quot;''' tab for that device.&lt;br /&gt;
&lt;br /&gt;
[[File:logs_button.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
Let's take as example the HomeCare plugin. Users should be notify when a sensor has not been tripped for a specified amount of time. Here is how &amp;quot;Alerts&amp;quot; page for HomeCare plugin looks like:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you can see the '''source''' of this notification is our HomeCare plugin, '''type''' for it is &amp;quot;user created trigger&amp;quot; and '''desctiption''' is the one we added in plugin.&lt;br /&gt;
&lt;br /&gt;
And here is the detailed message for this notification:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification_alert.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
== Alert HTTP Request ==&lt;br /&gt;
&lt;br /&gt;
http://IP:3480/data_request?id=add_alert&amp;amp;device=DEVICE_ID&amp;amp;type=3&amp;amp;source=3&amp;amp;description=ALERT_DESCRIPTION&amp;amp;users=USERS_LIST&lt;br /&gt;
&lt;br /&gt;
* DEVICE_ID - device # that generates the alert;&lt;br /&gt;
* ALERT_TYPE - &amp;quot;user created trigger&amp;quot; alert;&lt;br /&gt;
* ALERT_SOURCE - trigger event type message in detailed description;&lt;br /&gt;
* ALERT_DESCRIPTION - URL encoded message used as description for the alert;&lt;br /&gt;
* USERS_LIST - a list with user ID separated by commas that should be notify[left blank if no user notification is required].&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Alerts</id>
		<title>Alerts</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Alerts"/>
				<updated>2014-10-02T13:44:30Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
3rd party developers can now use the alert system in plugins. They can generate different alert types with or without user notification. Alert messages generated by a device can be seen in '''&amp;quot;Logs&amp;quot;''' tab for that device.&lt;br /&gt;
&lt;br /&gt;
[[File:logs_button.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
Let's take as example the HomeCare plugin. Users should be notify when a sensor has not been tripped for a specified amount of time. Here is how &amp;quot;Alerts&amp;quot; page for HomeCare plugin looks like:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
As you can see the '''source''' of this notification is our HomeCare plugin, '''type''' for it is &amp;quot;user created trigger&amp;quot; and '''desctiption''' is the one we added in plugin.&lt;br /&gt;
&lt;br /&gt;
And here is the detailed message for this notification:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification_alert.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
== Alert Request ==&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Alerts</id>
		<title>Alerts</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Alerts"/>
				<updated>2014-10-02T13:37:17Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: Created page with &amp;quot;= Introduction =  3rd party developers can now use the alert system in plugins. They can generate different alert types with or without user notification. Alert messages gener...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
3rd party developers can now use the alert system in plugins. They can generate different alert types with or without user notification. Alert messages generated by a device can be seen in '''&amp;quot;Logs&amp;quot;''' tab for that device.&lt;br /&gt;
&lt;br /&gt;
[[File:logs_button.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
Let's take as example the HomeCare plugin. Users should be notify when a sensor has not been tripped for a specified amount of time. Here is how &amp;quot;Alerts&amp;quot; page for HomeCare plugin looks like:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification.png|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
And here is the notification message:&lt;br /&gt;
&lt;br /&gt;
[[File:homecare_notification_alert.png|image|none|caption]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:Homecare_notification_alert.png</id>
		<title>File:Homecare notification alert.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:Homecare_notification_alert.png"/>
				<updated>2014-10-02T13:36:45Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:Homecare_notification.png</id>
		<title>File:Homecare notification.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:Homecare_notification.png"/>
				<updated>2014-10-02T13:34:01Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:Logs_button.png</id>
		<title>File:Logs button.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:Logs_button.png"/>
				<updated>2014-10-02T13:31:30Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Extra_Submenu_Items</id>
		<title>Extra Submenu Items</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Extra_Submenu_Items"/>
				<updated>2014-10-01T10:22:33Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inrodution ==&lt;br /&gt;
A number of extra submenu items can be created for each device type by using the definition supplied in plugin .json file.&lt;br /&gt;
&lt;br /&gt;
These items will be created under ‘Apps’ menu item.&lt;br /&gt;
&lt;br /&gt;
They can be used to execute user defined functions which display content on the right part of the Web interface (the same way the other submenu items do).&lt;br /&gt;
&lt;br /&gt;
== How To ==&lt;br /&gt;
&lt;br /&gt;
==== In your plugin .json file, insert the following construction after ‘eventList2’: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;submenuItems&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;my_plugin_first_submenu&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;My first submenu&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;ScriptName&amp;quot;: &amp;quot;my_plugin.js&amp;quot;,&lt;br /&gt;
            &amp;quot;Function&amp;quot;: &amp;quot;MY_PLUGIN.first_submenu&amp;quot;,&lt;br /&gt;
            &amp;quot;Parameters&amp;quot;: {&lt;br /&gt;
                &amp;quot;name&amp;quot;: &amp;quot;John Doe&amp;quot;,&lt;br /&gt;
                &amp;quot;age&amp;quot;: &amp;quot;84&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
            &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;my_plugin_second_submenu&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;My second submenu&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;Invisible&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;ScriptName&amp;quot;: &amp;quot;my_plugin.js&amp;quot;,&lt;br /&gt;
            &amp;quot;Function&amp;quot;: &amp;quot;MY_PLUGIN.second_submenu&amp;quot;,&lt;br /&gt;
            &amp;quot;Parameters&amp;quot;: {}&lt;br /&gt;
        }&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This construction defines two submenu items. &lt;br /&gt;
&lt;br /&gt;
* '''id''': integer, must be unique&lt;br /&gt;
* '''Label''': a JSON object containing two keys:&lt;br /&gt;
** '''lang_tag''': string used by localized UIs&lt;br /&gt;
** '''text''': string which represents the text that is going to be displayed if localization fails&lt;br /&gt;
* '''Function''': string specifying the function to be called when clicking on this submenu item&lt;br /&gt;
* '''Parameters''': a JSON object containing the parameters which are to be called with the function&lt;br /&gt;
* '''ScriptName''': string specifying the .js file which must be loaded in order to find the function&lt;br /&gt;
* '''Invisible''': (optional) - integer, if set to 1, the submenu item will be hidden and can be programmatically displayed&lt;br /&gt;
&lt;br /&gt;
==== Create or edit your ‘my_plugin.js’ file and add the following lines: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MY_PLUGIN = (function() {&lt;br /&gt;
    return {&lt;br /&gt;
        first_submenu: function(obj) {&lt;br /&gt;
            try {&lt;br /&gt;
                // get the parent element...&lt;br /&gt;
                var $parent = $('#' + View.containerForExtraSubmenuItem());&lt;br /&gt;
                &lt;br /&gt;
                // create a new DOM element...&lt;br /&gt;
                var $c = $('&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;');&lt;br /&gt;
                $c.html('I am '+obj['name']+' ! Give me $' +obj['ammount']+ ' !');&lt;br /&gt;
                &lt;br /&gt;
                // and append it to the parent...&lt;br /&gt;
                $c.appendTo($parent);&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                Utils.logError('Error in first_submenu(): ' + e);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
})();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Code explained''': it is executed after clicking on the submenu item defined. It creates a DOM element which displays a message. That DOM element is appended to a container where all DOM manipulation from the plugin will reside.&lt;br /&gt;
&lt;br /&gt;
==== After the plugin is installed and a LU Reload is performed, click on ‘Apps’ -&amp;gt; ‘My first submenu’ and the page will look something like this: ====&lt;br /&gt;
&lt;br /&gt;
[[File:submenu.jpg|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The function supplied was executed and the content is displayed on the right side of the page.&lt;br /&gt;
&lt;br /&gt;
Note the absence of ‘My second submenu’ from the list (because was marked with property ‘Invisible’).&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Extra_Submenu_Items</id>
		<title>Extra Submenu Items</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Extra_Submenu_Items"/>
				<updated>2014-10-01T10:19:28Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: Created page with &amp;quot;== Inrodution == A number of extra submenu items can be created for each device type by using the definition supplied in plugin .json file.  These items will be created under ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inrodution ==&lt;br /&gt;
A number of extra submenu items can be created for each device type by using the definition supplied in plugin .json file.&lt;br /&gt;
&lt;br /&gt;
These items will be created under ‘Apps’ menu item.&lt;br /&gt;
&lt;br /&gt;
They can be used to execute user defined functions which display content on the right part of the Web interface (the same way the other submenu items do).&lt;br /&gt;
&lt;br /&gt;
== How To ==&lt;br /&gt;
&lt;br /&gt;
==== In your plugin .json file, insert the following construction after ‘eventList2’: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;submenuItems&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;my_plugin_first_submenu&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;My first submenu&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;ScriptName&amp;quot;: &amp;quot;my_plugin.js&amp;quot;,&lt;br /&gt;
            &amp;quot;Function&amp;quot;: &amp;quot;MY_PLUGIN.first_submenu&amp;quot;,&lt;br /&gt;
            &amp;quot;Parameters&amp;quot;: {&lt;br /&gt;
                &amp;quot;name&amp;quot;: &amp;quot;John Doe&amp;quot;,&lt;br /&gt;
                &amp;quot;age&amp;quot;: &amp;quot;84&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;id&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
            &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;my_plugin_second_submenu&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;My second submenu&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;Invisible&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
            &amp;quot;ScriptName&amp;quot;: &amp;quot;my_plugin.js&amp;quot;,&lt;br /&gt;
            &amp;quot;Function&amp;quot;: &amp;quot;MY_PLUGIN.second_submenu&amp;quot;,&lt;br /&gt;
            &amp;quot;Parameters&amp;quot;: {}&lt;br /&gt;
        }&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This construction defines two submenu items. &lt;br /&gt;
&lt;br /&gt;
* id: integer, must be unique&lt;br /&gt;
* Label: a JSON object containing two keys:&lt;br /&gt;
** lang_tag: string used by localized UIs&lt;br /&gt;
** text: string which represents the text that is going to be displayed if localization fails&lt;br /&gt;
* Function: string specifying the function to be called when clicking on this submenu item&lt;br /&gt;
* Parameters: a JSON object containing the parameters which are to be called with the function&lt;br /&gt;
* ScriptName: string specifying the .js file which must be loaded in order to find the function&lt;br /&gt;
* Invisible: (optional) - integer, if set to 1, the submenu item will be hidden and can be programmatically displayed&lt;br /&gt;
&lt;br /&gt;
==== Create or edit your ‘my_plugin.js’ file and add the following lines: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MY_PLUGIN = (function() {&lt;br /&gt;
    return {&lt;br /&gt;
        first_submenu: function(obj) {&lt;br /&gt;
            try {&lt;br /&gt;
                // get the parent element...&lt;br /&gt;
                var $parent = $('#' + View.containerForExtraSubmenuItem());&lt;br /&gt;
                &lt;br /&gt;
                // create a new DOM element...&lt;br /&gt;
                var $c = $('&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;');&lt;br /&gt;
                $c.html('I am '+obj['name']+' ! Give me $' +obj['ammount']+ ' !');&lt;br /&gt;
                &lt;br /&gt;
                // and append it to the parent...&lt;br /&gt;
                $c.appendTo($parent);&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                Utils.logError('Error in first_submenu(): ' + e);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
})();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Code explained''': it is executed after clicking on the submenu item defined. It creates a DOM element which displays a message. That DOM element is appended to a container where all DOM manipulation from the plugin will reside.&lt;br /&gt;
&lt;br /&gt;
==== After the plugin is installed and a LU Reload is performed, click on ‘Apps’ -&amp;gt; ‘My first submenu’ and the page will look something like this: ====&lt;br /&gt;
&lt;br /&gt;
[[File:submenu.jpg|image|none|caption]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The function supplied was executed and the content is displayed on the right side of the page.&lt;br /&gt;
&lt;br /&gt;
Note the absence of ‘My second submenu’ from the list (because was marked with property ‘Invisible’).&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:Submenu.jpg</id>
		<title>File:Submenu.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:Submenu.jpg"/>
				<updated>2014-10-01T10:15:04Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/JavaScript_API</id>
		<title>JavaScript API</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/JavaScript_API"/>
				<updated>2014-10-01T08:51:13Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Tabs&amp;quot;: [&lt;br /&gt;
       {&lt;br /&gt;
           &amp;quot;Label&amp;quot;: {&lt;br /&gt;
               &amp;quot;lang_tag&amp;quot;: &amp;quot;users&amp;quot;,&lt;br /&gt;
               &amp;quot;text&amp;quot;: &amp;quot;Users&amp;quot; &lt;br /&gt;
           },&lt;br /&gt;
           &amp;quot;Position&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
           &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
           &amp;quot;ScriptName&amp;quot;: &amp;quot;I_HomeCare.js&amp;quot;,&lt;br /&gt;
           &amp;quot;Function&amp;quot;: &amp;quot;showUsers&amp;quot;&lt;br /&gt;
       }, &amp;lt;/pre&amp;gt; &lt;br /&gt;
To generate a tab using your JavaScript functions you need to specify this by setting ''TabType'' to '''''javascript'''''. Then, you need to specify the script file's name and which function in this file will be used to draw the tab's content. That function will have one argument, which is the device number.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== &amp;amp;lt;functionName&amp;amp;gt; (deviceNumber)  ====&lt;br /&gt;
&lt;br /&gt;
This is the tab rendering function. The [[#set_panel_html_.28html.29 | set_panel_html]] function must be called at the end.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceNumber (number)&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables  ==&lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud  ====&lt;br /&gt;
&lt;br /&gt;
This is the user data. &lt;br /&gt;
&lt;br /&gt;
*'''Type''': object &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**devices (array) &lt;br /&gt;
**scenes (array) &lt;br /&gt;
**users (array) &lt;br /&gt;
**rooms (array) &lt;br /&gt;
**eventList (array) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.devices  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**device_type (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**category_num (number) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==== jsonp.ud.scenes  ====&lt;br /&gt;
&lt;br /&gt;
*'''Type''': array &lt;br /&gt;
*'''Members''': &lt;br /&gt;
**id (number) &lt;br /&gt;
**name (string) &lt;br /&gt;
**room (number) &lt;br /&gt;
**Timer_ids (array) &lt;br /&gt;
**Timer (object) &lt;br /&gt;
**etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Functions  ==&lt;br /&gt;
&lt;br /&gt;
==== get_device_state (deviceId, serviceId, variable, dynamic)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is taken from ''lu_status'', else, the variable's value is taken from ''user_data''. ''user_data'' is read at Luup startup, so for variables that change their value frequently (like Watts, Temperature, etc.) ''dynamic'' should be '''1'''.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*variable value (string or ''undefined'')&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_device_state (deviceId, serviceId, variable, value, dynamic) ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*deviceId (number)&lt;br /&gt;
*serviceId (string)&lt;br /&gt;
*variable (string)&lt;br /&gt;
*value (string)&lt;br /&gt;
*dynamic (number): if '''1''', the variable's value is saved to ''lu_status'' (the value is lost after Luup is restarted), else, the variable's value is saved to a copy of ''user_data''; the real user_data is updated when LuaUPnP is restarted.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*''true'' if the operation succeeded, ''false'' otherwise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== _console (str)  ====&lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*str (string): text to be written in the console. You need to have FireBug installed in order to have a console.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== set_panel_html (html)  ====&lt;br /&gt;
&lt;br /&gt;
Used in the tab rendering functions. &lt;br /&gt;
&lt;br /&gt;
'''Input:''' &lt;br /&gt;
&lt;br /&gt;
*html (string): The html to be used for generating the tab content.&lt;br /&gt;
&lt;br /&gt;
'''Output:''' &lt;br /&gt;
&lt;br /&gt;
*nothing&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= JavaScript API for UI7 =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
One of the new features of UI7 is the Javascript API for writing plugins. This is a free programming interface which is robust, well documented and comes with a guarantee that it will be compatible with the following UI releases.&lt;br /&gt;
&lt;br /&gt;
'''''What is this “API” ?'''''&lt;br /&gt;
&lt;br /&gt;
Simply said: it is a layer between the UI and the plugin developer. This way, the developer can use the features available in the UI by interacting only with the API. By using the new features available in the API, the overall user experience can be visibly improved.&lt;br /&gt;
&lt;br /&gt;
'''''How does it work ?'''''&lt;br /&gt;
&lt;br /&gt;
The API comes in the form of a library which exposes to the developer the objects and methods/functions needed to implement functionality in their plugins.&lt;br /&gt;
&lt;br /&gt;
'''''How is this different from the previous way of writing plugins ?'''''&lt;br /&gt;
&lt;br /&gt;
The developers were writing Javascript code and they had full access to the core of the application. There were a couple of objects and functions written by the UI team which were easing the work for the developer.&lt;br /&gt;
By using the new API, the developer can write code without interfering with the core of the application.&lt;br /&gt;
&lt;br /&gt;
'''''What is new ?'''''&lt;br /&gt;
&lt;br /&gt;
* The developer can write the plugin without interfering with any other code except the API. This means there are a great bundle of methods like setters and getters which help writing good code.&lt;br /&gt;
* UI team can make any changes to the core of the application, but as long as the API stays the same, the plugins will work. This way, the application can be improved and the developer won’t have to fix the code in order for it to work. New versions of the UI can be launched and the plugins will be compatible.&lt;br /&gt;
* Event handling - the application will notify the plugin (via the API) about the events that happen inside. Consider, for example, the addition of a new device to the unit. The developer will know, by simply listening to an event, that a device was added and so, (s)he will write the code in such a way that it will take into account the event. The user experience will be greatly improved.&lt;br /&gt;
* Asynchronous getters and setters - because most of the actions that happen inside the UI is asynchronous, so are the API’s method written. Most of them have a signature like this: function getXXX(obj, onSuccess, onFailure), where ‘onSuccess’ and ‘onFailure’ are callback functions which are called based on the result of the call.&lt;br /&gt;
* No more global variables to manipulate. Everything is handled through getters/setters via API.&lt;br /&gt;
* An API reference documentation: every method and its parameters is carefully documented so that the developer would know what the function does, how to call it and what it will return.&lt;br /&gt;
* A couple of guidelines will be given to help developers write better code in such a way that two different plugins won’t “harm” each other. The module pattern will be used as a design pattern in order to put a plugin code inside a namespace. Also, this module helps in writing code which is easier to read and use.&lt;br /&gt;
* It will be easier for the developers to write the code by using a new feature in the UI which generates the skeleton for the plugin.&lt;br /&gt;
&lt;br /&gt;
'''''What is the API reference documentation ?'''''&lt;br /&gt;
&lt;br /&gt;
This is the part which makes the API usable. Every aspect of the API, no matter how trivial, will be stated explicitly. It contains:&lt;br /&gt;
&lt;br /&gt;
* a description of all the data structures it depends upon&lt;br /&gt;
* a description of all the function signatures:&lt;br /&gt;
** function names&lt;br /&gt;
** function parameters (names and types)&lt;br /&gt;
** return type of the function&lt;br /&gt;
** if it throws any exceptions or not&lt;br /&gt;
&lt;br /&gt;
'''''Where is the list of functions which were replaced ?'''''&lt;br /&gt;
&lt;br /&gt;
In the API reference documentation the developer can find out if a function replaces an old one.&lt;br /&gt;
&lt;br /&gt;
'''''Why should a developer write plugins using the API when it can do some “reverse engineering” and directly access any object/functionality of the application ?'''''&lt;br /&gt;
&lt;br /&gt;
It is not mandatory to write the code for the plugin this way. Probably the plugin will work as long as changes are not made in the core of the application, but the API comes also with a guarantee that after application changes, the plugins will continue to work. The UI team and plugin developers have the same goal: to deliver the best experience to the user. This is where the API comes into place - an interface between the two.&lt;br /&gt;
&lt;br /&gt;
'''''Will the API be rewritten with each new UI release ?'''''&lt;br /&gt;
&lt;br /&gt;
No. It will be improved. The goal of the API is to provide a stable interface to the developer so that when changing the core of the application it won’t be necessary to rewrite the plugins.&lt;br /&gt;
&lt;br /&gt;
'''''Is this API going to change in the near future ?'''''&lt;br /&gt;
&lt;br /&gt;
It can be changed. There will be parts of it which are going to be marked as ‘deprecated’. This means that the parts will be candidates for being removed, or modified in a backward incompatible way. The developers will be advised on how are they to change their code in order to use the features which replace the deprecated parts.&lt;br /&gt;
&lt;br /&gt;
'''''Is the API complete ?'''''&lt;br /&gt;
&lt;br /&gt;
Almost. Most of the functionality is there, but developers are encouraged to request new features from the API which will be added in future releases.&lt;br /&gt;
&lt;br /&gt;
== Guidelines on writing Javascript code for plugins in UI7 ==&lt;br /&gt;
&lt;br /&gt;
* Use the module pattern to organize your code inside a namespace. Choose a well defined name for your namespace.&lt;br /&gt;
* Generate an UUID for your plugin. This way you can use the events engine.&lt;br /&gt;
* Use the provided API plugins to perform most of your stuff. If you can’t find an implemented method inside the API you can ASK for an implementation to it.&lt;br /&gt;
* '''NEVER USE''' variables/functions which are not accessible through API ! They can be changed or removed at any time.&lt;br /&gt;
* If you need to do a background job (ex: start a timer), use the events engine and register a ‘cleanup’ function in which you finish the job (clear the timer).&lt;br /&gt;
* We encourage the use of try { … } catch { … } blocks everywhere in your functions so that errors don’t get propagated to the top of the application.&lt;br /&gt;
* Start from the skeleton provided and expand it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function (api) {&lt;br /&gt;
// example of unique identifier for this plugin...&lt;br /&gt;
var uuid = 'B971F6C4-F315-4E2E-AD08-F029A9777517';&lt;br /&gt;
&lt;br /&gt;
var myModule = {};&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
        // register to event ‘on_ui_cpanel_before_close’...&lt;br /&gt;
        api.registerEventHandler('on_ui_cpanel_before_close', myModule, ‘cleanUp’);&lt;br /&gt;
        // and do something... &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function cleanUp() {&lt;br /&gt;
        // perform clean up...&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    myModule = {&lt;br /&gt;
        uuid: uuid,&lt;br /&gt;
        doSomething: doSomething,&lt;br /&gt;
        cleanUp: cleanUp&lt;br /&gt;
    };&lt;br /&gt;
    return myModule;&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Your plugin functions will be accessible via ''MyPlugin.doSomething()'' construction.&lt;br /&gt;
When the user will leave the cpanel, your plugin will be noticed via event ''‘on_ui_cpanel_before_close’''; this way you can perform the necessary cleanup.&lt;br /&gt;
&lt;br /&gt;
== JavaScript API ==&lt;br /&gt;
&lt;br /&gt;
''Defined in'': api.js&lt;br /&gt;
&lt;br /&gt;
=== Class Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
'''API(config, application, ui)''' &lt;br /&gt;
&lt;br /&gt;
- API class for plugins&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} config - holds configuration data&lt;br /&gt;
* {object} application - application layer&lt;br /&gt;
* {object} ui - interface&lt;br /&gt;
&lt;br /&gt;
=== Method Summary ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== {Object} cloneObject(obj) ====&lt;br /&gt;
&lt;br /&gt;
- Clones a given object&lt;br /&gt;
&lt;br /&gt;
- Replaces: cloneObject()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {object} obj - object to be cloned&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object}&lt;br /&gt;
&lt;br /&gt;
==== {string} getCpanelContent() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves cpanel content&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {string} HTML code set in cpanel&lt;br /&gt;
&lt;br /&gt;
==== {number} getCpanelDeviceId() ====&lt;br /&gt;
&lt;br /&gt;
- Returns device id for current opened cpanel or 0 if not found&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number} - device ID&lt;br /&gt;
&lt;br /&gt;
==== getCurrentHouseMode(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve the current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {number} getDeviceIndex(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device index for given device id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_index()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDeviceObject(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device object given its id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_device_obj()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {number}&lt;br /&gt;
&lt;br /&gt;
===={object} getDeviceState(deviceId, service, variable, options)====&lt;br /&gt;
&lt;br /&gt;
- Retrieves device state for a device (it can be either read from user data or lu status, depending on the options set)&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {object} options Optional - list of options like: 'dynamic': (true - lu_status will be used [default], false - user_data will be used)&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {object} value for a given variable&lt;br /&gt;
&lt;br /&gt;
==== {Object|Boolean} getDeviceTemplate(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns device template for a given device id&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {Object|Boolean}&lt;br /&gt;
&lt;br /&gt;
==== {*} getDisplayedDeviceName(deviceId) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves displayed device name or 'unnamed device' if device doesn't have a name or undefined if device not found&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} if device is found a string which contains the device name or 'Unnamed device' if device name is not set, or undefined if device wasn't found&lt;br /&gt;
&lt;br /&gt;
==== {*} getEventDefinition(deviceType) ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves event list for a given device type&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_event_definition() &lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} deviceType - type of device&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== {*} getListOfDevices() ====&lt;br /&gt;
&lt;br /&gt;
- Returns the list of devices from userdata&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*}&lt;br /&gt;
&lt;br /&gt;
==== getLuSdata(onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Performs a data request to retrieve lu_sdata&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== {*|Object} getRoomObject(roomId) ====&lt;br /&gt;
&lt;br /&gt;
- Returns room object given a room id&lt;br /&gt;
&lt;br /&gt;
- Replaces: get_room_by_id()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} roomId - id of the room&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*|Object}&lt;br /&gt;
&lt;br /&gt;
==== {*} getUserData() ====&lt;br /&gt;
&lt;br /&gt;
- Retrieves userData or null if error&lt;br /&gt;
&lt;br /&gt;
- Replaces: jsonp.ud&lt;br /&gt;
&lt;br /&gt;
'''Returns:'''&lt;br /&gt;
&lt;br /&gt;
* {*} object containing userdata&lt;br /&gt;
&lt;br /&gt;
==== registerEventHandler(eventName, object, functionName) ====&lt;br /&gt;
&lt;br /&gt;
- Register an event handler.&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} eventName - name of the event to register to&lt;br /&gt;
* {object} object - the object which registers to the event&lt;br /&gt;
* {string} functionName - the name of the function to be executed if event triggers&lt;br /&gt;
&lt;br /&gt;
==== runUpnpCode(code, options, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Runs given Upnp code&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} code - code to execute&lt;br /&gt;
* {object} options Optional - optionally options to be supplied (will be documented later)&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setCpanelContent(html) ====&lt;br /&gt;
&lt;br /&gt;
- Sets content for the cpanel&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_panel_html()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {string} html - the new content of the cpanel&lt;br /&gt;
&lt;br /&gt;
==== setCurrentHouseMode(modeValue, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets current house mode&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} modeValue - new value for the house mode&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;br /&gt;
&lt;br /&gt;
==== setDeviceStateVariable(deviceId, service, variable, value, onSuccess, onFailure, context) ====&lt;br /&gt;
&lt;br /&gt;
- Sets state for a device variable using variableset request.&lt;br /&gt;
&lt;br /&gt;
- Replaces: set_device_state()&lt;br /&gt;
&lt;br /&gt;
'''Parameters:'''&lt;br /&gt;
&lt;br /&gt;
* {number} deviceId - id of the device&lt;br /&gt;
* {string} service - name of the service&lt;br /&gt;
* {string} variable - name of the variable&lt;br /&gt;
* {*} value - new value for the variable&lt;br /&gt;
* {*} onSuccess Optional - function to be called if the call is successfull&lt;br /&gt;
* {*} onFailure Optional - function to be called if the call fails&lt;br /&gt;
* {object} context Optional - context in which to execute the functions of success and/or failure&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:TopNavigationTab.jpg</id>
		<title>File:TopNavigationTab.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:TopNavigationTab.jpg"/>
				<updated>2014-09-30T15:54:05Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugins:_Static_JSON_file</id>
		<title>Luup plugins: Static JSON file</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugins:_Static_JSON_file"/>
				<updated>2014-09-30T15:53:47Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
Starting in UI4, Luup plugins can specify a ''static JSON'' file.  This file describes how the plugin appears in the web interface.&lt;br /&gt;
&lt;br /&gt;
=What the static JSON file controls=&lt;br /&gt;
&lt;br /&gt;
* The icon used by the plugin in the dashboard.&lt;br /&gt;
* The text that displays in the one-to-two-row status message in the dashboard.&lt;br /&gt;
* Whether the icon changes depending on the value of a variable in the device (for example, a binary light's icon changes from lit to unlit).&lt;br /&gt;
* The tabs that appear in the device's detail dialog (when you click the wrench/spanner).&lt;br /&gt;
* The content of these tabs.&lt;br /&gt;
* The triggers or events that are available for the device in the &amp;quot;Triggers&amp;quot; or &amp;quot;Events&amp;quot; tag of a scene.&lt;br /&gt;
&lt;br /&gt;
=Referencing the static JSON file from the Device XML file=&lt;br /&gt;
&lt;br /&gt;
The device XML file (customarly '''D_PluginName.xml''') contains a reference to the static JSON file, in the '''staticJson''' element.  Place the element as a child of the '''device''' element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
  &amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
  &amp;lt;root xmlns=&amp;quot;urn:schemas-upnp-org:device-1-0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;specVersion&amp;gt;&amp;lt;!-- ... --&amp;gt;&amp;lt;/specVersion&amp;gt;&lt;br /&gt;
    &amp;lt;device&amp;gt;&lt;br /&gt;
      &amp;lt;deviceType&amp;gt;urn:schemas-futzle-com:device:holidayvirtualswitch:1&amp;lt;/deviceType&amp;gt;&lt;br /&gt;
      &amp;lt;staticJson&amp;gt;D_HolidayVirtualSwitch1.json&amp;lt;/staticJson&amp;gt;&lt;br /&gt;
      &amp;lt;!-- ... --&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Capitalization is important, as with all XML.&lt;br /&gt;
&lt;br /&gt;
The static JSON file is customarily called '''D_PluginName.json'''.&lt;br /&gt;
&lt;br /&gt;
=The static JSON file=&lt;br /&gt;
&lt;br /&gt;
The static JSON file is a single JSON object (associative array).&lt;br /&gt;
&lt;br /&gt;
==Root keys==&lt;br /&gt;
&lt;br /&gt;
These keys have been seen at the top level in static JSON files in the wild:&lt;br /&gt;
&lt;br /&gt;
; flashicon&lt;br /&gt;
: The device's icon, as a string.  Despite the name, the icon is no longer related to Adobe Flash in UI4 or UI5. See [[Luup plugin icons]].&lt;br /&gt;
; imgIconBody&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconDimmable&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconTurnable&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconMin&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; imgIconMax&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; halloIconsDir&lt;br /&gt;
: Ignored in UI5.&lt;br /&gt;
; inScene&lt;br /&gt;
: When included and set equal to one, it enables any buttons, etc located on the &amp;quot;dashboard box&amp;quot;, so they can be selected in the scene editor for use in scenes, rather than being grayed out.&lt;br /&gt;
; DisplayStatus&lt;br /&gt;
: A JSON object (associative array).  For devices where the icon changes based on a variable's value, describes which variable, and the range of values that produce different icon images.  See [[Luup plugin icons]].&lt;br /&gt;
; state_icons&lt;br /&gt;
: A JSON array.  For devices where the icon changes based on a variable's value, describes which icon files exist.  See [[Luup plugin icons]]. Used only in firmware 1.5.401 or later.&lt;br /&gt;
; doc_url&lt;br /&gt;
: A JSON object (associative array). In UI5, the only item in this object which is used is doc_page. It controls which page in docs5.mios.com is brought up when you click on the help ('''?''') icon in the device control panel.&lt;br /&gt;
; Tabs&lt;br /&gt;
: A JSON array.  Describes the tabs in the detail dialog, and what subset of the first tab appears in the dashboard.  See [[Luup plugin tabs]].&lt;br /&gt;
; DeviceType&lt;br /&gt;
: A JSON string.  Must match the '''deviceType''' element in the corresponding device XML ('''D_PluginName.xml''') file.&lt;br /&gt;
; eventList&lt;br /&gt;
: A JSON object (associative array).  Describes the events that this plugin can produce.  Events are triggers that can fire off actions in scenes.  This key is required for UI4, and obsoleted in UI5. For UI5, use the eventList2 tag, which has a different format. For compatibility with both UI4 and UI5 you need the same information in both keys. See [[UI4 UI5 Migration]] for more information.&lt;br /&gt;
; eventList2&lt;br /&gt;
: see eventList, above.&lt;br /&gt;
; sceneList&lt;br /&gt;
: A JSON object (associative array).  Describes the actions that this plugin can perform (for instance, as the action in a scene). This key is not required and is ignored in UI5, however it is needed for UI4 compatibility. See [[UI4 UI5 Migration]] for more information about its format.&lt;br /&gt;
= UI7 Updates =&lt;br /&gt;
&lt;br /&gt;
* '''default_icon'''&lt;br /&gt;
: replace the old &amp;quot;flashicon&amp;quot; from UI5. See [[Luup plugin icons]]&lt;br /&gt;
* '''state_icons'''&lt;br /&gt;
: state_icons mechanism has changed in UI7. Please see [[Luup plugin icons]]&lt;br /&gt;
* '''TopNavigationTab''' = '''top_navigation_tab'''&lt;br /&gt;
&lt;br /&gt;
In device cpanel, tabs can be placed either in the top part or in the bottom. By default they are put in the bottom part. You can mark your tabs with a special flag so that they can be placed in top navigation bar of the cpanel.&lt;br /&gt;
If two or more tabs are marked with ‘'''TabType=”flash”'''’, only the first one found will be placed in top navigation bar. If you want all of them to be placed there, you have to add ‘'''top_navigation_tab'''’ to each one.&lt;br /&gt;
Let’s assume you have a plugin named ‘MyPlugin’ and you want to put a button in the top navigation bar, which, when clicked, will display a message in the cpanel.&lt;br /&gt;
&lt;br /&gt;
* Add the following lines to the .json device file (D_MyPlugin.json), in the Tabs section:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
          &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                &amp;quot;lang_tag&amp;quot;: &amp;quot;About&amp;quot;,&lt;br /&gt;
                &amp;quot;text&amp;quot;: &amp;quot;About&amp;quot;&lt;br /&gt;
          },&lt;br /&gt;
              &amp;quot;TopNavigationTab&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
          &amp;quot;Position&amp;quot;: &amp;quot;4&amp;quot;,&lt;br /&gt;
          &amp;quot;TabType&amp;quot;: &amp;quot;javascript&amp;quot;,&lt;br /&gt;
          &amp;quot;ScriptName&amp;quot;: &amp;quot;J_MyPlugin.js&amp;quot;,&lt;br /&gt;
          &amp;quot;Function&amp;quot;: &amp;quot;MyPlugin.about&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice the property ‘'''TopNavigationTab'''’ set to the value of ‘1’. This is the line that specifies where to place the tab in cpanel. If you set a value different than 1, the tab will be placed in the bottom part of the cpanel, so always use ‘1’ if you want the tab in the top bar. You can also use ‘'''top_navigation_tab'''’.&lt;br /&gt;
&lt;br /&gt;
* Add the following lines of code to your .js file (J_MyPlugin.js):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var MyPlugin = (function(api){&lt;br /&gt;
    return {&lt;br /&gt;
        about: function() {&lt;br /&gt;
            try {              &lt;br /&gt;
                var html = '&amp;lt;div&amp;gt;This is all about me !&amp;lt;/div&amp;gt;';&lt;br /&gt;
             api.setCpanelContent(html);&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                Utils.logError('Error in MyPlugin.about(): ' + e);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
})(api);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Perform a lu reload, enter device cpanel and click on ‘About’ button (which is in the top navigation bar of the cpanel) and the result will be something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:TopNavigationTab.jpg|image|left]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugin_tabs</id>
		<title>Luup plugin tabs</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugin_tabs"/>
				<updated>2014-09-30T15:38:47Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;br&amp;gt; The '''Tabs''' key in the [[Luup plugins: Static JSON file|static JSON file]] performs two duties in the UI4 HTML interface: &lt;br /&gt;
&lt;br /&gt;
*It controls how the device appears in the dashboard. &lt;br /&gt;
*It controls how each tab appears in the the device's detailed dialog.&lt;br /&gt;
&lt;br /&gt;
The value of the '''Tabs''' key is a JSON array. Each array element is a JSON object (associative array). &lt;br /&gt;
&lt;br /&gt;
= Required tab fields  =&lt;br /&gt;
&lt;br /&gt;
These fields must be present in each JSON object in the tab list: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object containing two keys: '''lang_tag''' (a string) is not displayed in the HTML interface but may be used by localized UIs; '''text''' (a string) is displayed in the tab's handle at the top of the dialog. &lt;br /&gt;
;'''Position''' &lt;br /&gt;
:A string which contains a number matching the relative position of this tab in relation to the other tabs. The leftmost tab has value &amp;quot;0&amp;quot;, the next tab &amp;quot;1&amp;quot;, and so on. &lt;br /&gt;
;'''TabType''' &lt;br /&gt;
:A string which describes how the content of the tab is to be generated. The value may be one of '''javascript''' or '''flash'''. These are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== TabType javascript  ==&lt;br /&gt;
&lt;br /&gt;
The '''javascript''' tab type executes client-side JavaScript, producing an HTML fragment which forms the body of the tab. These additional keys are required in the tab JSON object: &lt;br /&gt;
&lt;br /&gt;
;'''ScriptName''' &lt;br /&gt;
:The name of the JavaScript file. Conventionally, plugin JavaScript files are named '''J_PluginName.js'''. &lt;br /&gt;
;'''Function''' &lt;br /&gt;
:The function inside the JavaScript file which will be called to produce the HTML.&lt;br /&gt;
&lt;br /&gt;
The JavaScript code has access to most Luup variables through the [[JavaScript API]]. &lt;br /&gt;
&lt;br /&gt;
== TabType flash  ==&lt;br /&gt;
&lt;br /&gt;
The '''flash''' tab type creates a tab body with a simple page-description language. Each component of the page is placed into the body at the position specified. You can't place a '''Control''' on the dashboard unless you place it in a '''ControlGroup''', which in turn must be placed in a '''SceneGroup''': &lt;br /&gt;
&lt;br /&gt;
;'''UI5 SceneGroup'''&lt;br /&gt;
&lt;br /&gt;
''SceneGroup'' is a new type of container, similar to a ControlGroup, but with some key differences: it is customizable (by setting its position and dimensions) and it defines the behavior of the buttons assigned to the same state variable. If two buttons in the same SceneGroup are assigned to the same variable, only one of them can be activated in the scene editor (radio buttons behavior). If two buttons assigned to the same variable are in different SceneGroups, both can be activated at the same time in the scene editor (checkboxes behavior). &lt;br /&gt;
&lt;br /&gt;
It has the following tags: &lt;br /&gt;
&lt;br /&gt;
*'''id''': A numeric value (positive integer numbers). &lt;br /&gt;
*'''top''': The offset from the device header. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''left''': The offset from the device icon. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''x''', '''y''': the dimensions of the SceneGroup. e.g If I have two horizontally aligned buttons in the SceneGroup, ''x'' will be ''2'' and ''y'' will be ''1''.&lt;br /&gt;
&lt;br /&gt;
A ''SceneGroup'' can contain one or more ''ControlGroups''. &lt;br /&gt;
&lt;br /&gt;
;'''ControlGroup''' &lt;br /&gt;
:Required only if the first tab is also used to display elements on the dashboard. See ''Dashboard appearance'' below. &lt;br /&gt;
;'''Control''' &lt;br /&gt;
:An array of JSON objects, each representing a control on the tab. The Control Types are described further below. Each control object in the array can also contain: &lt;br /&gt;
:'''ControlGroup''' - a reference to the control's control group &lt;br /&gt;
:'''top''' - does what? &lt;br /&gt;
:'''left''' - does what?&lt;br /&gt;
&lt;br /&gt;
== Control Types  ==&lt;br /&gt;
&lt;br /&gt;
The '''Control''' array contains JSON objects (associative arrays), one per item in the tab body. An item is either a static text label, a variable, an input field, or a button or slider. This is handled by setting the '''ControlType''' key on the object. &lt;br /&gt;
&lt;br /&gt;
=== ControlType label  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''label''', a fixed label is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the content of the label. In UI5 on the &amp;quot;Dashboard&amp;quot;, the text is rendered by passing it in the &amp;quot;Title&amp;quot; attribute of a Div statement, so it can only be plain text, (as opposed to say HTML). However in the tabs, it is placed in a Div statement so HTML, such as a URL link, can be rendered. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the label is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType variable  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''variable''', the contents of a Luup variable are displayed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with six keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the variable's value is placed in the tab), '''Service''' (a string containing the Service Id of the variable to be displayed), and '''Variable''' (a string containing the name of the variable to be displayed).&lt;br /&gt;
&lt;br /&gt;
=== ControlType input  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''input''', a text box for the user to type a string is placed in the tab. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''ID''' &lt;br /&gt;
:A string which other controls (buttons) will use to refer to the string that the user has typed into this field. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the text box is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType button  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''button''', a clickable button is placed at the specified coordinates. The button will appear selected (depressed) or unselected based on the value of a variable, permitting sets of buttons to act as radio buttons. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the text inside the button. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with up to seven keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), and (optionally) '''Value''' (a string, &amp;quot;1&amp;quot; if omitted). The specified variable's value controls whether the button appears selected (if the variable matches '''Value''') or not selected (if the variable doesn't match). &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching an input control on the page (for a user-entered parameter value).&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''slider''', a draggable slider is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with nine keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), '''MinValue''' and '''MaxValue''' (both strings containing numbers, controlling what range of values the slider takes) and '''ID''' (a string, used in the '''Command''' to refer to the position the user has dragged the slider to). The specified variable's value is used to display the slider's current position. &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching the slider's ID (for a value matching what the user has dragged the slider to). &lt;br /&gt;
;'''ControlHeader''' &lt;br /&gt;
:Optional. If present, must have string value &amp;quot;1&amp;quot;. When set, the slider's label and value are displayed. Otherwise only the slider is shown. (TODO: This is from reverse-engineering the JavaScript code. Test this.)&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider_vertical  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_Heater1.json, D_HVAC_ZoneThermostat1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType checkbox  ===&lt;br /&gt;
&lt;br /&gt;
:As of UI5 firmware 1.5.622, checkboxes are only half-baked and not usable in &amp;quot;flash&amp;quot; style tabs. If you need check-boxes, radio buttons, pop-up menus, etc. in your tab, you need to create a Javascript tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType image  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType image_player  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType js_button  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
= Dashboard appearance  =&lt;br /&gt;
&lt;br /&gt;
The first array element in the '''Tabs''' field is special. If it is of type '''flash''' then a subset of the controls on the tab can be chosen to display on the UI4 dashboard.&lt;br /&gt;
&lt;br /&gt;
== Control Groups  ==&lt;br /&gt;
&lt;br /&gt;
The dashboard box for a device has room for two rows of information and controls. These are called ''Control Groups''.&lt;br /&gt;
&lt;br /&gt;
The tab object must contain the key '''ControlGroup''', which specifies how the dashboard's two available rows of information are to be handled. '''ControlGroup''' is a JSON array containing JSON objects (associative arrays). Each object has the following keys:&lt;br /&gt;
&lt;br /&gt;
;'''id''' &lt;br /&gt;
:A string containing a number, &amp;quot;1&amp;quot; for the first object, &amp;quot;2&amp;quot; for the second, and so on. &lt;br /&gt;
;'''isSingle''' &lt;br /&gt;
:UI4: If this key is present and contains the value &amp;quot;1&amp;quot;, then this control group is combined with other control groups that have '''isSingle''' similarly set onto the same row. For an example of this, see the On/Off buttons of the Binary Switch and Dimmable Switch static JSON files. &lt;br /&gt;
:UI5: Since controls cannot be grouped in drop-down lists anymore, this tag has a different role in UI5. When isSingle is &amp;quot;1&amp;quot;, the buttons in the ControlGroup will have a background (e.g. the BinaryLight buttons). If isSingle is missing, the buttons won't have a background. That is the button shape is not shown; only the button text will show. &lt;br /&gt;
;'''type''' &lt;br /&gt;
:If this key is present and contains the value &amp;quot;info&amp;quot;, then the controls displayed on this row are not clickable. If this key is absent, buttons may be used in the control group.&lt;br /&gt;
&lt;br /&gt;
== Making a control appear on the dashboard  ==&lt;br /&gt;
&lt;br /&gt;
All control types (label, variable, button, input, slider) can appear in the dashboard. However, by default, controls in the first tab's detail view do not appear in the dashboard. To make a control's text appear in the dashboard, add a '''ControlGroup''' to the control's JSON object. The value is a string containing a number, matching the '''id''' of one of the Tab's overall '''ControlGroup''' key. The dashboard will concatenate all of a control group's controls in the order they are presented in the '''Control''' array, and display them in a single row of text. &lt;br /&gt;
&lt;br /&gt;
== Keeping controls together  ==&lt;br /&gt;
&lt;br /&gt;
Some controls may not make sense if presented individually (for instance, an input for an alarm PIN and a &amp;quot;disarm&amp;quot; button). To keep these controls together, add a '''ControlPair''' key to all of the controls that have to appear together. Use the same value (a number in a string) for all of them. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= UI7 Updates =&lt;br /&gt;
&lt;br /&gt;
=== ControlType multi_state_button === &lt;br /&gt;
This is a new type of control in UI7 and works as a “toggle” button. It is used for On/Off, Armed/Disarmed etc buttons.&lt;br /&gt;
&lt;br /&gt;
As an example, here is the definition from the .json file of the Door/Window sensor needed to create this kind of control:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
&amp;quot;ControlType&amp;quot;: &amp;quot;multi_state_button&amp;quot;,&lt;br /&gt;
&amp;quot;top&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
&amp;quot;left&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;states&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
                  &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                      &amp;quot;lang_tag&amp;quot;: &amp;quot;ui7_cmd_arm&amp;quot;,&lt;br /&gt;
                      &amp;quot;text&amp;quot;: &amp;quot;Arm&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                     &amp;quot;Display&amp;quot;: {&lt;br /&gt;
                         &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                         &amp;quot;Variable&amp;quot;: &amp;quot;Armed&amp;quot;,&lt;br /&gt;
                           &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;Command&amp;quot;: {&lt;br /&gt;
                         “Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                           &amp;quot;Action&amp;quot;: &amp;quot;SetArmed&amp;quot;,&lt;br /&gt;
                           &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
                                   {&lt;br /&gt;
                                        &amp;quot;Name&amp;quot;: &amp;quot;newArmedValue&amp;quot;,&lt;br /&gt;
                                        &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                           ]&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlCode&amp;quot;: &amp;quot;arm&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                     &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                           &amp;quot;lang_tag&amp;quot;: &amp;quot;ui7_cmd_bypass&amp;quot;,&lt;br /&gt;
                           &amp;quot;text&amp;quot;: &amp;quot;Bypass&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                     &amp;quot;Display&amp;quot;: {&lt;br /&gt;
                           &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                            &amp;quot;Variable&amp;quot;: &amp;quot;Armed&amp;quot;,&lt;br /&gt;
                            &amp;quot;Value&amp;quot;: &amp;quot;0&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;Command&amp;quot;: {&lt;br /&gt;
                           &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                            &amp;quot;Action&amp;quot;: &amp;quot;SetArmed&amp;quot;,&lt;br /&gt;
                            &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
                                {&lt;br /&gt;
                                        &amp;quot;Name&amp;quot;: &amp;quot;newArmedValue&amp;quot;,&lt;br /&gt;
                                        &amp;quot;Value&amp;quot;: &amp;quot;0&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                            ]&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlCode&amp;quot;: &amp;quot;bypass&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
        ]&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''ControlGroup''' - an integer - has the same behaviour as in previous UIs &lt;br /&gt;
* '''ControlType''' - a string which must be set to ‘multi_state_button’&lt;br /&gt;
* '''top''' - an integer specifying the row from the control group where the control will be placed&lt;br /&gt;
* '''left''' - an integer which specifies which column will the control be placed in&lt;br /&gt;
* '''states''' - an array of objects, each object representing a different state for the button; each object has the following properties:&lt;br /&gt;
** '''Lable''' - a JSON object with two keys:&lt;br /&gt;
*** '''lang_tag''' - a string used for localization&lt;br /&gt;
*** '''text''' - the string displayed if localization fails&lt;br /&gt;
** '''Display''' - a JSON object with the following keys:&lt;br /&gt;
*** '''Service''' - a string containing the service id&lt;br /&gt;
*** '''Variable''' - a string containing the name of the variable&lt;br /&gt;
*** '''Value''' - a number which represents the value of the state in which the control must be in order for this state to be displayed/marked as selected&lt;br /&gt;
** '''Command''' - a JSON object with the following properties:&lt;br /&gt;
*** '''Service''' - a string with the service id of the action which this state will perform&lt;br /&gt;
*** '''Action''' - a string representing the name of the action to be executed&lt;br /&gt;
** '''Parameters''' - an array of JSON objects holding the parameters to pass to the action&lt;br /&gt;
* '''ControlCode''' - a string containing the control code of this control (it is recommended to be unique for each device type)&lt;br /&gt;
&lt;br /&gt;
As you can see, the multi_state_button is a merge resulted from two controls of type button.&lt;br /&gt;
&lt;br /&gt;
[[File:MotionSensor.jpg|image|left]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugin_tabs</id>
		<title>Luup plugin tabs</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugin_tabs"/>
				<updated>2014-09-30T15:38:09Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;br&amp;gt; The '''Tabs''' key in the [[Luup plugins: Static JSON file|static JSON file]] performs two duties in the UI4 HTML interface: &lt;br /&gt;
&lt;br /&gt;
*It controls how the device appears in the dashboard. &lt;br /&gt;
*It controls how each tab appears in the the device's detailed dialog.&lt;br /&gt;
&lt;br /&gt;
The value of the '''Tabs''' key is a JSON array. Each array element is a JSON object (associative array). &lt;br /&gt;
&lt;br /&gt;
= Required tab fields  =&lt;br /&gt;
&lt;br /&gt;
These fields must be present in each JSON object in the tab list: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object containing two keys: '''lang_tag''' (a string) is not displayed in the HTML interface but may be used by localized UIs; '''text''' (a string) is displayed in the tab's handle at the top of the dialog. &lt;br /&gt;
;'''Position''' &lt;br /&gt;
:A string which contains a number matching the relative position of this tab in relation to the other tabs. The leftmost tab has value &amp;quot;0&amp;quot;, the next tab &amp;quot;1&amp;quot;, and so on. &lt;br /&gt;
;'''TabType''' &lt;br /&gt;
:A string which describes how the content of the tab is to be generated. The value may be one of '''javascript''' or '''flash'''. These are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== TabType javascript  ==&lt;br /&gt;
&lt;br /&gt;
The '''javascript''' tab type executes client-side JavaScript, producing an HTML fragment which forms the body of the tab. These additional keys are required in the tab JSON object: &lt;br /&gt;
&lt;br /&gt;
;'''ScriptName''' &lt;br /&gt;
:The name of the JavaScript file. Conventionally, plugin JavaScript files are named '''J_PluginName.js'''. &lt;br /&gt;
;'''Function''' &lt;br /&gt;
:The function inside the JavaScript file which will be called to produce the HTML.&lt;br /&gt;
&lt;br /&gt;
The JavaScript code has access to most Luup variables through the [[JavaScript API]]. &lt;br /&gt;
&lt;br /&gt;
== TabType flash  ==&lt;br /&gt;
&lt;br /&gt;
The '''flash''' tab type creates a tab body with a simple page-description language. Each component of the page is placed into the body at the position specified. You can't place a '''Control''' on the dashboard unless you place it in a '''ControlGroup''', which in turn must be placed in a '''SceneGroup''': &lt;br /&gt;
&lt;br /&gt;
;'''UI5 SceneGroup'''&lt;br /&gt;
&lt;br /&gt;
''SceneGroup'' is a new type of container, similar to a ControlGroup, but with some key differences: it is customizable (by setting its position and dimensions) and it defines the behavior of the buttons assigned to the same state variable. If two buttons in the same SceneGroup are assigned to the same variable, only one of them can be activated in the scene editor (radio buttons behavior). If two buttons assigned to the same variable are in different SceneGroups, both can be activated at the same time in the scene editor (checkboxes behavior). &lt;br /&gt;
&lt;br /&gt;
It has the following tags: &lt;br /&gt;
&lt;br /&gt;
*'''id''': A numeric value (positive integer numbers). &lt;br /&gt;
*'''top''': The offset from the device header. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''left''': The offset from the device icon. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''x''', '''y''': the dimensions of the SceneGroup. e.g If I have two horizontally aligned buttons in the SceneGroup, ''x'' will be ''2'' and ''y'' will be ''1''.&lt;br /&gt;
&lt;br /&gt;
A ''SceneGroup'' can contain one or more ''ControlGroups''. &lt;br /&gt;
&lt;br /&gt;
;'''ControlGroup''' &lt;br /&gt;
:Required only if the first tab is also used to display elements on the dashboard. See ''Dashboard appearance'' below. &lt;br /&gt;
;'''Control''' &lt;br /&gt;
:An array of JSON objects, each representing a control on the tab. The Control Types are described further below. Each control object in the array can also contain: &lt;br /&gt;
:'''ControlGroup''' - a reference to the control's control group &lt;br /&gt;
:'''top''' - does what? &lt;br /&gt;
:'''left''' - does what?&lt;br /&gt;
&lt;br /&gt;
== Control Types  ==&lt;br /&gt;
&lt;br /&gt;
The '''Control''' array contains JSON objects (associative arrays), one per item in the tab body. An item is either a static text label, a variable, an input field, or a button or slider. This is handled by setting the '''ControlType''' key on the object. &lt;br /&gt;
&lt;br /&gt;
=== ControlType label  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''label''', a fixed label is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the content of the label. In UI5 on the &amp;quot;Dashboard&amp;quot;, the text is rendered by passing it in the &amp;quot;Title&amp;quot; attribute of a Div statement, so it can only be plain text, (as opposed to say HTML). However in the tabs, it is placed in a Div statement so HTML, such as a URL link, can be rendered. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the label is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType variable  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''variable''', the contents of a Luup variable are displayed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with six keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the variable's value is placed in the tab), '''Service''' (a string containing the Service Id of the variable to be displayed), and '''Variable''' (a string containing the name of the variable to be displayed).&lt;br /&gt;
&lt;br /&gt;
=== ControlType input  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''input''', a text box for the user to type a string is placed in the tab. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''ID''' &lt;br /&gt;
:A string which other controls (buttons) will use to refer to the string that the user has typed into this field. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the text box is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType button  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''button''', a clickable button is placed at the specified coordinates. The button will appear selected (depressed) or unselected based on the value of a variable, permitting sets of buttons to act as radio buttons. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the text inside the button. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with up to seven keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), and (optionally) '''Value''' (a string, &amp;quot;1&amp;quot; if omitted). The specified variable's value controls whether the button appears selected (if the variable matches '''Value''') or not selected (if the variable doesn't match). &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching an input control on the page (for a user-entered parameter value).&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''slider''', a draggable slider is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with nine keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), '''MinValue''' and '''MaxValue''' (both strings containing numbers, controlling what range of values the slider takes) and '''ID''' (a string, used in the '''Command''' to refer to the position the user has dragged the slider to). The specified variable's value is used to display the slider's current position. &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching the slider's ID (for a value matching what the user has dragged the slider to). &lt;br /&gt;
;'''ControlHeader''' &lt;br /&gt;
:Optional. If present, must have string value &amp;quot;1&amp;quot;. When set, the slider's label and value are displayed. Otherwise only the slider is shown. (TODO: This is from reverse-engineering the JavaScript code. Test this.)&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider_vertical  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_Heater1.json, D_HVAC_ZoneThermostat1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType checkbox  ===&lt;br /&gt;
&lt;br /&gt;
:As of UI5 firmware 1.5.622, checkboxes are only half-baked and not usable in &amp;quot;flash&amp;quot; style tabs. If you need check-boxes, radio buttons, pop-up menus, etc. in your tab, you need to create a Javascript tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType image  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType image_player  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType js_button  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
= Dashboard appearance  =&lt;br /&gt;
&lt;br /&gt;
The first array element in the '''Tabs''' field is special. If it is of type '''flash''' then a subset of the controls on the tab can be chosen to display on the UI4 dashboard.&lt;br /&gt;
&lt;br /&gt;
== Control Groups  ==&lt;br /&gt;
&lt;br /&gt;
The dashboard box for a device has room for two rows of information and controls. These are called ''Control Groups''.&lt;br /&gt;
&lt;br /&gt;
The tab object must contain the key '''ControlGroup''', which specifies how the dashboard's two available rows of information are to be handled. '''ControlGroup''' is a JSON array containing JSON objects (associative arrays). Each object has the following keys:&lt;br /&gt;
&lt;br /&gt;
;'''id''' &lt;br /&gt;
:A string containing a number, &amp;quot;1&amp;quot; for the first object, &amp;quot;2&amp;quot; for the second, and so on. &lt;br /&gt;
;'''isSingle''' &lt;br /&gt;
:UI4: If this key is present and contains the value &amp;quot;1&amp;quot;, then this control group is combined with other control groups that have '''isSingle''' similarly set onto the same row. For an example of this, see the On/Off buttons of the Binary Switch and Dimmable Switch static JSON files. &lt;br /&gt;
:UI5: Since controls cannot be grouped in drop-down lists anymore, this tag has a different role in UI5. When isSingle is &amp;quot;1&amp;quot;, the buttons in the ControlGroup will have a background (e.g. the BinaryLight buttons). If isSingle is missing, the buttons won't have a background. That is the button shape is not shown; only the button text will show. &lt;br /&gt;
;'''type''' &lt;br /&gt;
:If this key is present and contains the value &amp;quot;info&amp;quot;, then the controls displayed on this row are not clickable. If this key is absent, buttons may be used in the control group.&lt;br /&gt;
&lt;br /&gt;
== Making a control appear on the dashboard  ==&lt;br /&gt;
&lt;br /&gt;
All control types (label, variable, button, input, slider) can appear in the dashboard. However, by default, controls in the first tab's detail view do not appear in the dashboard. To make a control's text appear in the dashboard, add a '''ControlGroup''' to the control's JSON object. The value is a string containing a number, matching the '''id''' of one of the Tab's overall '''ControlGroup''' key. The dashboard will concatenate all of a control group's controls in the order they are presented in the '''Control''' array, and display them in a single row of text. &lt;br /&gt;
&lt;br /&gt;
== Keeping controls together  ==&lt;br /&gt;
&lt;br /&gt;
Some controls may not make sense if presented individually (for instance, an input for an alarm PIN and a &amp;quot;disarm&amp;quot; button). To keep these controls together, add a '''ControlPair''' key to all of the controls that have to appear together. Use the same value (a number in a string) for all of them. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= UI7 Updates =&lt;br /&gt;
&lt;br /&gt;
=== ControlType multi_state_button === &lt;br /&gt;
This is a new type of control in UI7 and works as a “toggle” button. It is used for On/Off, Armed/Disarmed etc buttons.&lt;br /&gt;
&lt;br /&gt;
As an example, here is the definition from the .json file of the Door/Window sensor needed to create this kind of control:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
&amp;quot;ControlType&amp;quot;: &amp;quot;multi_state_button&amp;quot;,&lt;br /&gt;
&amp;quot;top&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
&amp;quot;left&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
       &amp;quot;states&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
                  &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                      &amp;quot;lang_tag&amp;quot;: &amp;quot;ui7_cmd_arm&amp;quot;,&lt;br /&gt;
                      &amp;quot;text&amp;quot;: &amp;quot;Arm&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                     &amp;quot;Display&amp;quot;: {&lt;br /&gt;
                         &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                         &amp;quot;Variable&amp;quot;: &amp;quot;Armed&amp;quot;,&lt;br /&gt;
                           &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;Command&amp;quot;: {&lt;br /&gt;
                         “Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                           &amp;quot;Action&amp;quot;: &amp;quot;SetArmed&amp;quot;,&lt;br /&gt;
                           &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
                                   {&lt;br /&gt;
                                        &amp;quot;Name&amp;quot;: &amp;quot;newArmedValue&amp;quot;,&lt;br /&gt;
                                        &amp;quot;Value&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                           ]&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlCode&amp;quot;: &amp;quot;arm&amp;quot;&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
                     &amp;quot;Label&amp;quot;: {&lt;br /&gt;
                           &amp;quot;lang_tag&amp;quot;: &amp;quot;ui7_cmd_bypass&amp;quot;,&lt;br /&gt;
                           &amp;quot;text&amp;quot;: &amp;quot;Bypass&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlGroup&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
                     &amp;quot;Display&amp;quot;: {&lt;br /&gt;
                           &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                            &amp;quot;Variable&amp;quot;: &amp;quot;Armed&amp;quot;,&lt;br /&gt;
                            &amp;quot;Value&amp;quot;: &amp;quot;0&amp;quot;&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;Command&amp;quot;: {&lt;br /&gt;
                           &amp;quot;Service&amp;quot;: &amp;quot;urn:micasaverde-com:serviceId:SecuritySensor1&amp;quot;,&lt;br /&gt;
                            &amp;quot;Action&amp;quot;: &amp;quot;SetArmed&amp;quot;,&lt;br /&gt;
                            &amp;quot;Parameters&amp;quot;: [&lt;br /&gt;
                                {&lt;br /&gt;
                                        &amp;quot;Name&amp;quot;: &amp;quot;newArmedValue&amp;quot;,&lt;br /&gt;
                                        &amp;quot;Value&amp;quot;: &amp;quot;0&amp;quot;&lt;br /&gt;
                                    }&lt;br /&gt;
                            ]&lt;br /&gt;
                     },&lt;br /&gt;
                     &amp;quot;ControlCode&amp;quot;: &amp;quot;bypass&amp;quot;&lt;br /&gt;
              }&lt;br /&gt;
        ]&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''ControlGroup''' - an integer - has the same behaviour as in previous UIs &lt;br /&gt;
* '''ControlType''' - a string which must be set to ‘multi_state_button’&lt;br /&gt;
* '''top''' - an integer specifying the row from the control group where the control will be placed&lt;br /&gt;
* '''left''' - an integer which specifies which column will the control be placed in&lt;br /&gt;
* '''states''' - an array of objects, each object representing a different state for the button; each object has the following properties:&lt;br /&gt;
** '''Lable''' - a JSON object with two keys:&lt;br /&gt;
*** '''lang_tag''' - a string used for localization&lt;br /&gt;
*** '''text''' - the string displayed if localization fails&lt;br /&gt;
** '''Display''' - a JSON object with the following keys:&lt;br /&gt;
*** '''Service''' - a string containing the service id&lt;br /&gt;
*** '''Variable''' - a string containing the name of the variable&lt;br /&gt;
*** '''Value''' - a number which represents the value of the state in which the control must be in order for this state to be displayed/marked as selected&lt;br /&gt;
** '''Command''' - a JSON object with the following properties:&lt;br /&gt;
*** '''Service''' - a string with the service id of the action which this state will perform&lt;br /&gt;
*** '''Action''' - a string representing the name of the action to be executed&lt;br /&gt;
** '''Parameters''' - an array of JSON objects holding the parameters to pass to the action&lt;br /&gt;
* '''ControlCode''' - a string containing the control code of this control (it is recommended to be unique for each device type)&lt;br /&gt;
&lt;br /&gt;
As you can see, the multi_state_button is a merge resulted from two controls of type button.&lt;br /&gt;
&lt;br /&gt;
[[File:MotionSensor.jpg|thumb|left]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/File:MotionSensor.jpg</id>
		<title>File:MotionSensor.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/File:MotionSensor.jpg"/>
				<updated>2014-09-30T15:37:43Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugin_icons</id>
		<title>Luup plugin icons</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugin_icons"/>
				<updated>2014-09-30T15:01:44Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
The [[Luup plugins: Static JSON file|Luup plugin static JSON file]] describes the icon that appears in the dashboard of the UI4 web interface.&lt;br /&gt;
&lt;br /&gt;
=Icon format=&lt;br /&gt;
&lt;br /&gt;
All of Vera's icons are 42x42 pixel PNGs with transparency.  Icons of other sizes will be resized to 42x42.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The top-level key '''flashicon''' contains a string.  This string is the name of an image file.  The filename is either a relative path or a URL starting with &amp;quot;http&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==Relative paths==&lt;br /&gt;
&lt;br /&gt;
If the filename is a relative path, it is relative to the directory '''/www/cmh/skins/default''' on the Vera.  If the filename ends in the string &amp;quot;.swf&amp;quot;, this extension is changed to &amp;quot;.png&amp;quot;.  (This is presumably a holdover from UI3, which was flash-based.  In UI4, there is no reason to maintain this ruse, so just use the &amp;quot;.png&amp;quot; extension.)&lt;br /&gt;
&lt;br /&gt;
Files installed in the &amp;quot;icons&amp;quot; directory are:&lt;br /&gt;
* Binary_Light.png&lt;br /&gt;
* Binary_Light_0.png&lt;br /&gt;
* Binary_Light_100.png&lt;br /&gt;
* Dimmable_Light.png&lt;br /&gt;
* Dimmable_Light_0.png&lt;br /&gt;
* Dimmable_Light_100.png&lt;br /&gt;
* Dimmable_Light_25.png&lt;br /&gt;
* Dimmable_Light_50.png&lt;br /&gt;
* Dimmable_Light_75.png&lt;br /&gt;
* Door_Lock.png&lt;br /&gt;
* Door_Lock_0.png&lt;br /&gt;
* Door_Lock_100.png&lt;br /&gt;
* Generic_IO.png&lt;br /&gt;
* Humidity_Sensor.png&lt;br /&gt;
* IR_Transmitter.png&lt;br /&gt;
* Insteon.png&lt;br /&gt;
* Ip_Camera.png&lt;br /&gt;
* Light_Sensor.png&lt;br /&gt;
* Motion_Sensor.png&lt;br /&gt;
* Motion_Sensor_0.png&lt;br /&gt;
* Motion_Sensor_100.png&lt;br /&gt;
* Power_Meter.png&lt;br /&gt;
* Scenes.png&lt;br /&gt;
* Temperature_Sensor.png&lt;br /&gt;
* Thermostat.png&lt;br /&gt;
* USB_UIRT.png&lt;br /&gt;
* Window_Covering.png&lt;br /&gt;
* Zwave.png&lt;br /&gt;
* advanced.png&lt;br /&gt;
* default.png&lt;br /&gt;
* default_device.png&lt;br /&gt;
* default_panel.png&lt;br /&gt;
* default_plugins.png&lt;br /&gt;
* device.png&lt;br /&gt;
* devices.png&lt;br /&gt;
* energy.png&lt;br /&gt;
* findvera.png&lt;br /&gt;
* generic_icon.png&lt;br /&gt;
* generic_sensor.png&lt;br /&gt;
* intro.png&lt;br /&gt;
* location.png&lt;br /&gt;
* music_audio.png&lt;br /&gt;
* plugins.png&lt;br /&gt;
* users.png&lt;br /&gt;
&lt;br /&gt;
== URLs ==&lt;br /&gt;
&lt;br /&gt;
If the filename is a URL, it refers to a remote file on a web server.&lt;br /&gt;
&lt;br /&gt;
=Constant icons=&lt;br /&gt;
&lt;br /&gt;
For an icon that remains the same all the time, the '''flashicon''' key is all you need to provide.  Ensure that the static JSON file does not contain a '''DisplayStatus''' key, and you are done.&lt;br /&gt;
&lt;br /&gt;
= Variable icons  =&lt;br /&gt;
&lt;br /&gt;
For an icon that varies based on the value of a variable, place a '''DisplayStatus''' key at the top level of the static JSON file. Its value is a JSON object (associative array) with four keys: &lt;br /&gt;
&lt;br /&gt;
;Service &lt;br /&gt;
:The Service ID of the variable that controls the icon. This can be found in the matching device XML file, under the '''serviceId''' element. &lt;br /&gt;
;Variable &lt;br /&gt;
:The variable name of the variable that controls the icon. &lt;br /&gt;
;MinValue &lt;br /&gt;
:The value that this variable has when it is considered &amp;quot;off&amp;quot; or at &amp;quot;0%&amp;quot;. This can even be a string, if the variable is a string that takes two values. &lt;br /&gt;
;MaxValue &lt;br /&gt;
:The value that this variable has when it is considered &amp;quot;on&amp;quot; or at &amp;quot;100%&amp;quot;. This can even be a string, if the variable is a string that takes two values.&lt;br /&gt;
&lt;br /&gt;
Example for a binary switch: &lt;br /&gt;
&amp;lt;pre&amp;gt;  &amp;quot;DisplayStatus&amp;quot;: {&lt;br /&gt;
        &amp;quot;Service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
        &amp;quot;Variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
        &amp;quot;MinValue&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;MaxValue&amp;quot;: &amp;quot;1&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
Example for a variable which takes on a range of values. &lt;br /&gt;
&amp;lt;pre&amp;gt;  &amp;quot;DisplayStatus&amp;quot;: {&lt;br /&gt;
        &amp;quot;Service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:Dimming1&amp;quot;,&lt;br /&gt;
        &amp;quot;Variable&amp;quot;: &amp;quot;LoadLevelStatus&amp;quot;,&lt;br /&gt;
        &amp;quot;MinValue&amp;quot;: &amp;quot;0&amp;quot;,&lt;br /&gt;
        &amp;quot;MaxValue&amp;quot;: &amp;quot;100&amp;quot; &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
The filename in '''flashicon''' undergoes a special transformation for variable icons. The extension &amp;quot;.png&amp;quot; is changed to &amp;quot;_0.png&amp;quot;, &amp;quot;_25.png&amp;quot;, &amp;quot;_50.png&amp;quot;, &amp;quot;_75.png&amp;quot; or &amp;quot;_100.png&amp;quot; depending on the value of the service variable, linearly scaled from its range of 0:(MaxValue-MinValue) to 0:100. Values round up; 1-25 produces the &amp;quot;_25&amp;quot; image; 26-50 produces the &amp;quot;_50&amp;quot; image, and so on. For images which are not found (for instance, if the web server returns '''404 Not Found''') the default image is used. &lt;br /&gt;
&lt;br /&gt;
Consequently, at least three images, and as many as six, should be present for variable-icon plugins. For example, if '''flashicon''' contains '''&amp;lt;nowiki&amp;gt;http://example.com/image.png&amp;lt;/nowiki&amp;gt;''', the web server must be able to serve: &lt;br /&gt;
&lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image.png&amp;lt;/nowiki&amp;gt;''' (for when the plugin is loading in the Luup engine) &lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image_0.png&amp;lt;/nowiki&amp;gt;''' &lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image_100.png&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
and it should be able to serve (if the variable is a sliding scale): &lt;br /&gt;
&lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image_25.png&amp;lt;/nowiki&amp;gt;''' &lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image_50.png&amp;lt;/nowiki&amp;gt;''' &lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;http://example.com/image_75.png&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
== state_icons  ==&lt;br /&gt;
&lt;br /&gt;
From firmware 1.5.401 onwards, you must also tell the Static JSON file which icon files exist, with the '''state_icons''' key at the top level. The corresponding value is a JSON array of strings, the file names which should be displayed in the UI. This key was added to prevent the plethora of 404 errors that would appear in the JavaScript console. &lt;br /&gt;
&lt;br /&gt;
Currently each device can have a maximum of 5 icons. The formula for choosing the icon is this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var status = Variable / (MaxValue - MinValue);&lt;br /&gt;
var val = ceil( status * 4 );&lt;br /&gt;
var icon = baseIconName + &amp;quot;_&amp;quot; + (isNaN( val * 25 ) ? 0 : (val * 25)) + &amp;quot;.png&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
e.g. For the dimmable light, the formula would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var status = LoadLevelStatus / (100 - 0);&lt;br /&gt;
var val = ceil( status * 4 );&lt;br /&gt;
var icon = &amp;quot;Dimmable_Light&amp;quot; + &amp;quot;_&amp;quot; + (isNaN( val * 25 ) ? 0 : (val * 25)) + &amp;quot;.png&amp;quot;;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting intervals and icons are:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! LoadLevelStatus&lt;br /&gt;
! Icon&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| Dimmable_Light_0.png&lt;br /&gt;
|-&lt;br /&gt;
| 1 - 25&lt;br /&gt;
| Dimmable_Light_25.png&lt;br /&gt;
|-&lt;br /&gt;
| 26 - 50&lt;br /&gt;
| Dimmable_Light_50.png&lt;br /&gt;
|-&lt;br /&gt;
| 51 - 75&lt;br /&gt;
| Dimmable_Light_75.png&lt;br /&gt;
|-&lt;br /&gt;
| 76 - 100&lt;br /&gt;
| Dimmable_Light_100.png&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Cheating to get finer-grained variable icons  ==&lt;br /&gt;
&lt;br /&gt;
The JavaScript code that inserts the strings &amp;quot;_0&amp;quot; to &amp;quot;_100&amp;quot; into the image filename does not check that the raw variable value is in the range '''MinValue''' to '''MaxValue'''. By deliberately choosing a '''MaxValue''' less than the highest value that a variable can take, you can make the JavaScript load images with &amp;quot;_125&amp;quot;, &amp;quot;_150&amp;quot;, etc., effectively providing any number of images. '''MinValue''' is similarly handled, though the results are odd with negative variables or MinValue not equal to zero: the string inserted into the filename is &amp;quot;_-25&amp;quot;, &amp;quot;-50&amp;quot;, etc. &lt;br /&gt;
&lt;br /&gt;
That this trick works is probably accidental, and its behaviour probably should not be relied on.&lt;br /&gt;
= UI7 Icons=&lt;br /&gt;
&lt;br /&gt;
To avoid adding extra code to treat plugin icons, all plugin developers should take into consideration the following:&lt;br /&gt;
&lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;&amp;quot;default_icon&amp;quot;&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
&amp;quot;'''flashicon'''&amp;quot; - we don't use it any more, instead we will have &amp;quot;default_icon&amp;quot; as in the above example, which can be either the url from a image uploaded somewhere on the web or a image stored locally in skins/default/img/devices/device_sates/ . Please be sure if you choose the last method to not upload images with names identical to any of the existing device state icon files. Image resolution should be 50px x 50px.&lt;br /&gt;
*'''&amp;lt;nowiki&amp;gt;&amp;quot;state_icons&amp;quot;&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
If the device created by the plugin has states and we need to display them we will use this object. &amp;quot;img&amp;quot; is the state image, same as above, it's a url to a image uploaded on the web or the name of a image stored locally in skins/default/img/devices/device_sates/. &amp;quot;conditions&amp;quot; is an array of objects from which we build logical expressions and evaluate them to decide what icon to be used for what state. In the example above if in lu_status for a given binary light with &amp;quot;subcategory_num&amp;quot; = 0 ( this means indoor binary light , because we also have devices for outdoor use like the Jasco 45604) we find    service : &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;, variable : &amp;quot;Status&amp;quot; and the value from this pair is equal (&amp;quot;operator&amp;quot;) to the &amp;quot;value&amp;quot; (0) in the conditions object then we show the &amp;quot;binary_light_off.png&amp;quot; in the UI (light is off). A good example of usage for &amp;quot;subcategory_num&amp;quot; can be seen in the json definition of the motion sensor D_MotionSensor1.json - which serves as template for a number of types of sensors but I am not sure if this will be the case for plugins(&amp;quot;subcategory_num&amp;quot; is not mandatory). As I said &amp;quot;conditions&amp;quot; is an array of objects,     this means that if we want to display a certain icon based on more than 1 condition we can do so by adding to it more objects defining different conditions.&lt;br /&gt;
&lt;br /&gt;
Example:     &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;default_icon&amp;quot;: &amp;quot;binary_light_default.png&amp;quot;,&lt;br /&gt;
    &amp;quot;state_icons&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;img&amp;quot;: &amp;quot;binary_light_off.png&amp;quot;,&lt;br /&gt;
            &amp;quot;conditions&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;operator&amp;quot;: &amp;quot;==&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: 0,&lt;br /&gt;
                    &amp;quot;subcategory_num&amp;quot;: 0&lt;br /&gt;
                }&lt;br /&gt;
            ]&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;img&amp;quot;: &amp;quot;binary_light_on.png&amp;quot;,&lt;br /&gt;
            &amp;quot;conditions&amp;quot;: [&lt;br /&gt;
                {&lt;br /&gt;
                    &amp;quot;service&amp;quot;: &amp;quot;urn:upnp-org:serviceId:SwitchPower1&amp;quot;,&lt;br /&gt;
                    &amp;quot;variable&amp;quot;: &amp;quot;Status&amp;quot;,&lt;br /&gt;
                    &amp;quot;operator&amp;quot;: &amp;quot;==&amp;quot;,&lt;br /&gt;
                    &amp;quot;value&amp;quot;: 1,&lt;br /&gt;
                    &amp;quot;subcategory_num&amp;quot;: 0&lt;br /&gt;
                }&lt;br /&gt;
            ]&lt;br /&gt;
        }&lt;br /&gt;
    ],&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/Luup_plugin_tabs</id>
		<title>Luup plugin tabs</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/Luup_plugin_tabs"/>
				<updated>2014-09-30T14:54:25Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;br&amp;gt; The '''Tabs''' key in the [[Luup plugins: Static JSON file|static JSON file]] performs two duties in the UI4 HTML interface: &lt;br /&gt;
&lt;br /&gt;
*It controls how the device appears in the dashboard. &lt;br /&gt;
*It controls how each tab appears in the the device's detailed dialog.&lt;br /&gt;
&lt;br /&gt;
The value of the '''Tabs''' key is a JSON array. Each array element is a JSON object (associative array). &lt;br /&gt;
&lt;br /&gt;
= Required tab fields  =&lt;br /&gt;
&lt;br /&gt;
These fields must be present in each JSON object in the tab list: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object containing two keys: '''lang_tag''' (a string) is not displayed in the HTML interface but may be used by localized UIs; '''text''' (a string) is displayed in the tab's handle at the top of the dialog. &lt;br /&gt;
;'''Position''' &lt;br /&gt;
:A string which contains a number matching the relative position of this tab in relation to the other tabs. The leftmost tab has value &amp;quot;0&amp;quot;, the next tab &amp;quot;1&amp;quot;, and so on. &lt;br /&gt;
;'''TabType''' &lt;br /&gt;
:A string which describes how the content of the tab is to be generated. The value may be one of '''javascript''' or '''flash'''. These are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== TabType javascript  ==&lt;br /&gt;
&lt;br /&gt;
The '''javascript''' tab type executes client-side JavaScript, producing an HTML fragment which forms the body of the tab. These additional keys are required in the tab JSON object: &lt;br /&gt;
&lt;br /&gt;
;'''ScriptName''' &lt;br /&gt;
:The name of the JavaScript file. Conventionally, plugin JavaScript files are named '''J_PluginName.js'''. &lt;br /&gt;
;'''Function''' &lt;br /&gt;
:The function inside the JavaScript file which will be called to produce the HTML.&lt;br /&gt;
&lt;br /&gt;
The JavaScript code has access to most Luup variables through the [[JavaScript API]]. &lt;br /&gt;
&lt;br /&gt;
== TabType flash  ==&lt;br /&gt;
&lt;br /&gt;
The '''flash''' tab type creates a tab body with a simple page-description language. Each component of the page is placed into the body at the position specified. You can't place a '''Control''' on the dashboard unless you place it in a '''ControlGroup''', which in turn must be placed in a '''SceneGroup''': &lt;br /&gt;
&lt;br /&gt;
;'''UI5 SceneGroup'''&lt;br /&gt;
&lt;br /&gt;
''SceneGroup'' is a new type of container, similar to a ControlGroup, but with some key differences: it is customizable (by setting its position and dimensions) and it defines the behavior of the buttons assigned to the same state variable. If two buttons in the same SceneGroup are assigned to the same variable, only one of them can be activated in the scene editor (radio buttons behavior). If two buttons assigned to the same variable are in different SceneGroups, both can be activated at the same time in the scene editor (checkboxes behavior). &lt;br /&gt;
&lt;br /&gt;
It has the following tags: &lt;br /&gt;
&lt;br /&gt;
*'''id''': A numeric value (positive integer numbers). &lt;br /&gt;
*'''top''': The offset from the device header. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''left''': The offset from the device icon. It uses the same units as ''x'' and ''y''. &lt;br /&gt;
*'''x''', '''y''': the dimensions of the SceneGroup. e.g If I have two horizontally aligned buttons in the SceneGroup, ''x'' will be ''2'' and ''y'' will be ''1''.&lt;br /&gt;
&lt;br /&gt;
A ''SceneGroup'' can contain one or more ''ControlGroups''. &lt;br /&gt;
&lt;br /&gt;
;'''ControlGroup''' &lt;br /&gt;
:Required only if the first tab is also used to display elements on the dashboard. See ''Dashboard appearance'' below. &lt;br /&gt;
;'''Control''' &lt;br /&gt;
:An array of JSON objects, each representing a control on the tab. The Control Types are described further below. Each control object in the array can also contain: &lt;br /&gt;
:'''ControlGroup''' - a reference to the control's control group &lt;br /&gt;
:'''top''' - does what? &lt;br /&gt;
:'''left''' - does what?&lt;br /&gt;
&lt;br /&gt;
== Control Types  ==&lt;br /&gt;
&lt;br /&gt;
The '''Control''' array contains JSON objects (associative arrays), one per item in the tab body. An item is either a static text label, a variable, an input field, or a button or slider. This is handled by setting the '''ControlType''' key on the object. &lt;br /&gt;
&lt;br /&gt;
=== ControlType label  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''label''', a fixed label is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the content of the label. In UI5 on the &amp;quot;Dashboard&amp;quot;, the text is rendered by passing it in the &amp;quot;Title&amp;quot; attribute of a Div statement, so it can only be plain text, (as opposed to say HTML). However in the tabs, it is placed in a Div statement so HTML, such as a URL link, can be rendered. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the label is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType variable  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''variable''', the contents of a Luup variable are displayed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with six keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the variable's value is placed in the tab), '''Service''' (a string containing the Service Id of the variable to be displayed), and '''Variable''' (a string containing the name of the variable to be displayed).&lt;br /&gt;
&lt;br /&gt;
=== ControlType input  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''input''', a text box for the user to type a string is placed in the tab. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''ID''' &lt;br /&gt;
:A string which other controls (buttons) will use to refer to the string that the user has typed into this field. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with four keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers). This controls where the text box is placed in the tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType button  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''button''', a clickable button is placed at the specified coordinates. The button will appear selected (depressed) or unselected based on the value of a variable, permitting sets of buttons to act as radio buttons. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Label''' &lt;br /&gt;
:A JSON object with two keys: '''lang_tag''' is not displayed but can be used by localizing interfaces to translate the label text. '''text''' is displayed as the text inside the button. &lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with up to seven keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), and (optionally) '''Value''' (a string, &amp;quot;1&amp;quot; if omitted). The specified variable's value controls whether the button appears selected (if the variable matches '''Value''') or not selected (if the variable doesn't match). &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching an input control on the page (for a user-entered parameter value).&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider  ===&lt;br /&gt;
&lt;br /&gt;
With '''ControlType''' set to '''slider''', a draggable slider is placed at the specified coordinates. The following additional keys must also be provided: &lt;br /&gt;
&lt;br /&gt;
;'''Display''' &lt;br /&gt;
:A JSON object with nine keys: '''Top''', '''Left''', '''Width''', '''Height''' (all strings containing numbers, controlling where the button is placed in the tab), '''Service''' (a string containing the Service Id of a variable), and '''Variable''' (a string containing the name of a variable), '''MinValue''' and '''MaxValue''' (both strings containing numbers, controlling what range of values the slider takes) and '''ID''' (a string, used in the '''Command''' to refer to the position the user has dragged the slider to). The specified variable's value is used to display the slider's current position. &lt;br /&gt;
;'''Command''' &lt;br /&gt;
:A JSON object with three keys: '''Service''' (a string containing the service Id of an action that this device can perform), '''Action''' (a string containing the name of the action), and '''Parameters''' (a JSON array of JSON objects, forming the parameters to pass to the action). Each parameter object has a key '''Name''' for the parameter name, and either a key '''Value''' (for a fixed parameter value) or a key '''ID''' matching the slider's ID (for a value matching what the user has dragged the slider to). &lt;br /&gt;
;'''ControlHeader''' &lt;br /&gt;
:Optional. If present, must have string value &amp;quot;1&amp;quot;. When set, the slider's label and value are displayed. Otherwise only the slider is shown. (TODO: This is from reverse-engineering the JavaScript code. Test this.)&lt;br /&gt;
&lt;br /&gt;
=== ControlType slider_vertical  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_Heater1.json, D_HVAC_ZoneThermostat1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType checkbox  ===&lt;br /&gt;
&lt;br /&gt;
:As of UI5 firmware 1.5.622, checkboxes are only half-baked and not usable in &amp;quot;flash&amp;quot; style tabs. If you need check-boxes, radio buttons, pop-up menus, etc. in your tab, you need to create a Javascript tab.&lt;br /&gt;
&lt;br /&gt;
=== ControlType image  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType image_player  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
=== ControlType js_button  ===&lt;br /&gt;
&lt;br /&gt;
:Used in: D_DigitalSecurityCamera1.json&lt;br /&gt;
&lt;br /&gt;
= Dashboard appearance  =&lt;br /&gt;
&lt;br /&gt;
The first array element in the '''Tabs''' field is special. If it is of type '''flash''' then a subset of the controls on the tab can be chosen to display on the UI4 dashboard.&lt;br /&gt;
&lt;br /&gt;
== Control Groups  ==&lt;br /&gt;
&lt;br /&gt;
The dashboard box for a device has room for two rows of information and controls. These are called ''Control Groups''.&lt;br /&gt;
&lt;br /&gt;
The tab object must contain the key '''ControlGroup''', which specifies how the dashboard's two available rows of information are to be handled. '''ControlGroup''' is a JSON array containing JSON objects (associative arrays). Each object has the following keys:&lt;br /&gt;
&lt;br /&gt;
;'''id''' &lt;br /&gt;
:A string containing a number, &amp;quot;1&amp;quot; for the first object, &amp;quot;2&amp;quot; for the second, and so on. &lt;br /&gt;
;'''isSingle''' &lt;br /&gt;
:UI4: If this key is present and contains the value &amp;quot;1&amp;quot;, then this control group is combined with other control groups that have '''isSingle''' similarly set onto the same row. For an example of this, see the On/Off buttons of the Binary Switch and Dimmable Switch static JSON files. &lt;br /&gt;
:UI5: Since controls cannot be grouped in drop-down lists anymore, this tag has a different role in UI5. When isSingle is &amp;quot;1&amp;quot;, the buttons in the ControlGroup will have a background (e.g. the BinaryLight buttons). If isSingle is missing, the buttons won't have a background. That is the button shape is not shown; only the button text will show. &lt;br /&gt;
;'''type''' &lt;br /&gt;
:If this key is present and contains the value &amp;quot;info&amp;quot;, then the controls displayed on this row are not clickable. If this key is absent, buttons may be used in the control group.&lt;br /&gt;
&lt;br /&gt;
== Making a control appear on the dashboard  ==&lt;br /&gt;
&lt;br /&gt;
All control types (label, variable, button, input, slider) can appear in the dashboard. However, by default, controls in the first tab's detail view do not appear in the dashboard. To make a control's text appear in the dashboard, add a '''ControlGroup''' to the control's JSON object. The value is a string containing a number, matching the '''id''' of one of the Tab's overall '''ControlGroup''' key. The dashboard will concatenate all of a control group's controls in the order they are presented in the '''Control''' array, and display them in a single row of text. &lt;br /&gt;
&lt;br /&gt;
== Keeping controls together  ==&lt;br /&gt;
&lt;br /&gt;
Some controls may not make sense if presented individually (for instance, an input for an alarm PIN and a &amp;quot;disarm&amp;quot; button). To keep these controls together, add a '''ControlPair''' key to all of the controls that have to appear together. Use the same value (a number in a string) for all of them. &lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
= UI7 Updates =&lt;br /&gt;
&lt;br /&gt;
;'''TopNavigationTab''' = '''top_navigation_tab'''&lt;br /&gt;
: used to place a tab either in the top part or in the bottom of Cpannel. See [[Cpanel Top Navigation Tab]].&lt;br /&gt;
;'''&amp;quot;ControlType&amp;quot;: &amp;quot;multi_state_button&amp;quot;'''&lt;br /&gt;
: This is a new type of control in UI7 and works as a “toggle” button. It is used for On/Off, Armed/Disarmed etc buttons. See [[ControlType multi_state_button]]&lt;br /&gt;
;'''default_icon'''&lt;br /&gt;
: replace the old &amp;quot;flashicon&amp;quot; from UI5. See [[Luup plugin icons]]&lt;br /&gt;
;'''state_icons'''&lt;br /&gt;
: state_icons mechanism has changed in UI7. Please see [[Luup plugin icons]]&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-09-02T09:22:44Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==“Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Get “Mode” variable value ===&lt;br /&gt;
http://IP/data_request?id=variableget&amp;amp;Variable=Mode&lt;br /&gt;
=== Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	<entry>
		<id>http://wiki.mios.com/index.php/House_Modes</id>
		<title>House Modes</title>
		<link rel="alternate" type="text/html" href="http://wiki.mios.com/index.php/House_Modes"/>
				<updated>2014-09-02T09:20:28Z</updated>
		
		<summary type="html">&lt;p&gt;Andreimios: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==1. “Mode” top level attribute==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Mode value&lt;br /&gt;
! House Mode&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Home&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Away&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Night&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Vacation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.1 Get “Mode” variable value ===&lt;br /&gt;
http://IP/data_request?id=variableget&amp;amp;Variable=Mode&lt;br /&gt;
=== 1.2 Set “Mode” variable value ===&lt;br /&gt;
- luup.call_action(&amp;quot;urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;quot;,&amp;quot;SetHouseMode&amp;quot;, {Mode = value}, 0)&amp;lt;br&amp;gt;&lt;br /&gt;
- http://IP/port_3480/data_request?id=lu_action&amp;amp;serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&amp;amp;action=SetHouseMode&amp;amp;Mode=value&lt;br /&gt;
{| style=&amp;quot;border: 1px solid #000; border-collapse: collapse&amp;quot;&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 150px&amp;quot; rowspan=&amp;quot;2&amp;quot; | Action&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               colspan=&amp;quot;2&amp;quot; | Arguments&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000&amp;quot;               rowspan=&amp;quot;2&amp;quot; | Description&lt;br /&gt;
 |-&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 130px&amp;quot;             | Name&lt;br /&gt;
 ! style=&amp;quot;border: 1px solid #000; width: 140px&amp;quot;             | Type or Related Variable&lt;br /&gt;
 |-&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | SetHouseMode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | Mode&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; | ui1&lt;br /&gt;
 | style=&amp;quot;border: 1px solid #000&amp;quot; rowspan=&amp;quot;1&amp;quot; | Change House Mode&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. “ModeSetting” top level attribute – default/custom setting for each mode ==&lt;br /&gt;
&lt;br /&gt;
'''Default values:'''&amp;lt;br&amp;gt;&lt;br /&gt;
- “!1:DC;2:DC*;3:DC*;4:DC* ” - user didn't configured preset modes yet; info message on dashboard is displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
- “1:DC;2:DC*;3:DC*;4:DC*”  - user visited the preset mode page or configured the modes; info message on dashboard is not displayed;&amp;lt;br&amp;gt;&lt;br /&gt;
'''Legend :''' &amp;lt;br&amp;gt;&lt;br /&gt;
- “DC*” - corresponding mode have the default values;&amp;lt;br&amp;gt;&lt;br /&gt;
- “C*” - corresponding mode have custom values;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Get ModeSetting value'' : http://IP:3480/data_request?id=variableget&amp;amp;Variable=ModeSetting&amp;lt;br&amp;gt;&lt;br /&gt;
''Set ModeSetting value'' : http://IP:3480/data_request?id=variableset&amp;amp;Variable=ModeSetting&amp;amp;Value=value&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. “ModeSetting” device state variable ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3.1 “Choose sensors to arm ” section - all the devices with category 4 ( DEVICE_CATEGORY_SECURITY_SENSOR)  ===&lt;br /&gt;
- if this variable is blank or doesn't exist it means the device isn't configured yet. Once the device is configured, the variable will be set;&amp;lt;br&amp;gt;&lt;br /&gt;
- if “A” is present it means that the sensor is “Armed”;&amp;lt;br&amp;gt;&lt;br /&gt;
- if no value is present it means that the sensor is “Disarmed/Bypassed”. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example :&amp;lt;br&amp;gt; &lt;br /&gt;
“1:;2:A;3:A;4:A”&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Home” mode the sensor is Disarmed/Bypassed;&amp;lt;br&amp;gt;&lt;br /&gt;
- in “Away/Night/Vacation” modes the sensor is Armed;  &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3.2 “What to do if an armed sensor trips ? ” section - DEVICE_CATEGORY_SIREN &amp;amp; DEVICE_CATEGORY_SIREN ===&lt;br /&gt;
&lt;br /&gt;
The syntax used here is the same as for sensors&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3.3 “Who should be notified ?” section - look at the top level mode settings tag, like this: “1:D;2:DC*;3:DC*;4:DC*”  ===&lt;br /&gt;
&lt;br /&gt;
- if the “C” is present, it means “yes” &amp;lt;br&amp;gt;&lt;br /&gt;
- if the “*” is present, it means that all users will be notify. By default, all users are “yes” in all modes except “Home”. &amp;lt;br&amp;gt;&lt;br /&gt;
- if notification for an individual user is changed, then the “*” is changed to a comma separated list of the PK_Users that are set to “yes”. For example, if the PK_User=1818 is turned to “yes” for mode “Away/2” : “1:D;2:DC,1818;3:DC*;4:DC*”. If PK_User 1819 is added with “yes” also, then it will look like this:  “1:D;2:DC,1818,1819;3:DC*;4:DC*”and so on; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 3.4 “What to do when this mode is selected ?”  section  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 3.4.1 DEVICE_CATEGORY_HVAC ====&lt;br /&gt;
&lt;br /&gt;
No change = nothing; &amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = O; &amp;lt;br&amp;gt;&lt;br /&gt;
“Heat” = H; &amp;lt;br&amp;gt;&lt;br /&gt;
“Cool” = C; &amp;lt;br&amp;gt;&lt;br /&gt;
“Auto” = A; v&lt;br /&gt;
“,VALUE” = temperature; &amp;lt;br&amp;gt;&lt;br /&gt;
Example : &amp;lt;br&amp;gt;&lt;br /&gt;
“1:;2:H,72;3:C,73;4:A,74” - “no change” for mode #1, and the other three are heat, cool, auto.&lt;br /&gt;
&lt;br /&gt;
==== 3.4.2 DEVICE_CATEGORY_DOOR_LOCK ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“Lock” = L;&amp;lt;br&amp;gt;&lt;br /&gt;
“Unlock” = U.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:L;3:U;4:” - “no change” for mode #1 and #4, #2 - “Lock” and #3 - “Unlocked”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 3.4.3 DEVICE_CATEGORY_SWITCH &amp;amp; DEVICE_CATEGORY_DIMMABLE_LIGHT ====&lt;br /&gt;
&lt;br /&gt;
No Change = nothing;&amp;lt;br&amp;gt;&lt;br /&gt;
“On” = N;&amp;lt;br&amp;gt;&lt;br /&gt;
“Off” = F.&amp;lt;br&amp;gt;&lt;br /&gt;
Example : “1:;2:N;3:F;4:” - “no change” for mode #1 and #4, #2 - “On” and #3 - “Off”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Default modes ==&lt;br /&gt;
&lt;br /&gt;
DEVICE_CATEGORY_SECURITY_SENSOR (4)&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_GLASS (6)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_SMOKE (4)   			  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_CO (5)        		  1:A;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	DEVICE_SUBCATEGORY_DOOR (1)  			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
:	Other                        			  1:;2:A;3:;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SIREN (24)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_CAMERA (6)            			  1:;2:A;3:A;4:A&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_HVAC (5)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DOOR_LOCK (7)        			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_SWITCH (3)            			  1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;br /&gt;
DEVICE_CATEGORY_DIMMABLE_LIGHT (2)    		          1:;2:;3:;4:&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andreimios</name></author>	</entry>

	</feed>