<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.domoticz.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GuillaumeBarberousse</id>
	<title>Domoticz Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.domoticz.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GuillaumeBarberousse"/>
	<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/Special:Contributions/GuillaumeBarberousse"/>
	<updated>2026-09-20T07:09:24Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://wiki.domoticz.com/index.php?title=Developing_a_Python_plugin&amp;diff=18616</id>
		<title>Developing a Python plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Developing_a_Python_plugin&amp;diff=18616"/>
		<updated>2024-06-25T19:47:06Z</updated>

		<summary type="html">&lt;p&gt;GuillaumeBarberousse: Describe UpdateProperties, UpdateOptions and SuppressTriggers parameters in Update method of Plugin Extended framework&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
This page is aimed at developers wishing to improve Domoticz functionality via Python Plugins. If you simply want to use a plugin that a developer has already created for you, please see [[Using Python plugins]]. To see the Plugins already developed (for a reference) got to page [[Plugins]].&lt;br /&gt;
&lt;br /&gt;
The Domoticz Python Framework is not a general purpose Domoticz extension.  It is designed to allow developers to easily create an interface between a piece of Hardware (or Virtual Hardware) and Domoticz.  To that end it provides capabilities that seek to do the hard work for the developer leaving them to manage the messages that move backwards and forwards between the two.&lt;br /&gt;
&lt;br /&gt;
The Framework provides the plugin with a full Python 3 instance that exists for as long as Domoticz is running.  The plugin is called by Domoticz when relevant events occur so that it can manage connectivity to the hardware and state synchronisation.&lt;br /&gt;
&lt;br /&gt;
Multiple copies of the same plugin can run for users that have more than one instance of a particular hardware type.&lt;br /&gt;
&lt;br /&gt;
===Plugin Framework types===&lt;br /&gt;
There are current two variations of the Plugin Framework available, plugin authors can use either but &#039;&#039;&#039;not both&#039;&#039;&#039; at the same time:&lt;br /&gt;
&lt;br /&gt;
#Legacy Framework:  This has been stable for several years, invoked by importing &#039;Domoticz&#039; into the plugin&lt;br /&gt;
#Extended Framework:&lt;br /&gt;
#*Built on Legacy Framework but has a new object model and event localisation&lt;br /&gt;
#*Invoked by importing &#039;DomoticzEx&#039; into the plugin.&lt;br /&gt;
#*Creates a two layer mapping over the DeviceStatus table of Devices and Units&lt;br /&gt;
#*Plugins are not restricted to 256 Units (each Device can have 256 Units)&lt;br /&gt;
#*Supports encapsulation and limited polymorphism&lt;br /&gt;
&lt;br /&gt;
===Sleeping and multi-threading details:===&lt;br /&gt;
The following things should not be attempted using the Python Framework:&lt;br /&gt;
&lt;br /&gt;
*Waiting or sleepingin Domoticz callbacks. Plugin callbacks are single threaded so the whole plugin system will wait.&lt;br /&gt;
&lt;br /&gt;
The Python Framework has been uplifted to support multi-threaded plugins, key points:&lt;br /&gt;
&lt;br /&gt;
*Use of asynchronous code or modules and callback functions are now supported. These should function as expected.&lt;br /&gt;
*All threads started within the plugin (either directly or by imported modules) must be terminated by the plugin prior to the plugin stopping (&#039;onStop&#039; is the recommended place for this). Failure to do this will result in Python aborting Domoticz during hardware &#039;Stops&#039; &amp;amp;/or &#039;Updates&#039;. The Plugin Framework cannot enumerate threads started by the plugin or stop them (Python limitation) and any active threads when the plugin interpreter is destroyed will cause Python to abort. &#039;&#039;&#039;YOU HAVE BEEN WARNED !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
An example of a multi-threaded plugin including how to show running threads and thread shutdown can be found  [https://github.com/domoticz/domoticz/blob/development/plugins/examples/Mutli-Threaded.py here on Github]&lt;br /&gt;
&lt;br /&gt;
==Overall Structure==&lt;br /&gt;
The plugin documentation is split into two distinct parts:&lt;br /&gt;
&lt;br /&gt;
*Plugin Definition - Telling Domoticz about the plugin&lt;br /&gt;
*Runtime Structure - Interfaces and APIs to manage message flows between Domoticz and the hardware&lt;br /&gt;
&lt;br /&gt;
===Getting started===&lt;br /&gt;
If you are writing a Python plugin from scratch, you may want to begin by using the &#039;&#039;&#039;Script Template&#039;&#039;&#039; in &#039;&#039;domoticz/plugins/examples/BaseTemplate.py&#039;&#039;, which is also available from the github source repo at https://github.com/domoticz/domoticz/blob/master/plugins/examples/BaseTemplate.py&lt;br /&gt;
&lt;br /&gt;
==Plugin Definition==&lt;br /&gt;
To allow plugins to be added without the need for code changes to Domoticz itself requires that the plugins be exposed to Domoticz in a generic fashion.  This is done by having the plugins live in a set location so they can be found and via an XML definition embedded in the Python script itself that describes the parameters that the plugin requires.&lt;br /&gt;
&lt;br /&gt;
During Domoticz startup all directories directly under the &#039;plugins&#039; directory are scanned for python files named &amp;lt;code&amp;gt;plugin.py&amp;lt;/code&amp;gt; and those that contain definitions are indexed by Domoticz.  When the Hardware page is loaded the plugins defined in the index are merged into the list of available hardware and are indistinguishable from natively supported hardware.  For the example below the Kodi plugin would be in a file &amp;lt;code&amp;gt;domoticz/plugins/Kodi/plugin.py&amp;lt;/code&amp;gt;.  Some example Python scripts can be found in the &amp;lt;code&amp;gt;domoticz/plugins/examples&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
Plugin definitions expose some basic details to Domoticz and a list of the parameters that users can configure. Each defined parameters will appear as an input on the Hardware page when the plugin is selected in the dropdown. &lt;br /&gt;
&lt;br /&gt;
Definitions look like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;plugin key=&amp;quot;Kodi&amp;quot; name=&amp;quot;Kodi Players&amp;quot; author=&amp;quot;dnpwwo&amp;quot; version=&amp;quot;1.0.0&amp;quot; wikilink=&amp;quot;http://www.domoticz.com/wiki/plugins/Kodi.html&amp;quot; externallink=&amp;quot;https://kodi.tv/&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;&lt;br /&gt;
        &amp;lt;h2&amp;gt;Kodi Media Player Plugin&amp;lt;/h2&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
        &amp;lt;h3&amp;gt;Features&amp;lt;/h3&amp;gt;&lt;br /&gt;
        &amp;lt;ul style=&amp;quot;list-style-type:square&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Comes with three selectable icon sets: Default, Black and Round&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Display Domoticz notifications on Kodi screen if a Notifier name is specified and events configured for that notifier&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Multiple Shutdown action options&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;When network connectivity is lost the Domoticz UI will optionally show the device(s) with a Red banner&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
        &amp;lt;h3&amp;gt;Devices&amp;lt;/h3&amp;gt;&lt;br /&gt;
        &amp;lt;ul style=&amp;quot;list-style-type:square&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Status - Basic status indicator, On/Off. Also has icon for Kodi Remote popup&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Volume - Icon mutes/unmutes, slider shows/sets volume&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Source - Selector switch for content source: Video, Music, TV Shows, Live TV, Photos, Weather&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Playing - Icon Pauses/Resumes, slider shows/sets percentage through media&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Address&amp;quot; label=&amp;quot;IP Address&amp;quot; width=&amp;quot;200px&amp;quot; required=&amp;quot;true&amp;quot; default=&amp;quot;127.0.0.1&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Port&amp;quot; label=&amp;quot;Port&amp;quot; width=&amp;quot;30px&amp;quot; required=&amp;quot;true&amp;quot; default=&amp;quot;9090&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode1&amp;quot; label=&amp;quot;MAC Address&amp;quot; width=&amp;quot;150px&amp;quot; required=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode2&amp;quot; label=&amp;quot;Shutdown Command&amp;quot; width=&amp;quot;100px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Hibernate&amp;quot; value=&amp;quot;Hibernate&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Suspend&amp;quot; value=&amp;quot;Suspend&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Shutdown&amp;quot; value=&amp;quot;Shutdown&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Ignore&amp;quot; value=&amp;quot;Ignore&amp;quot; default=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode3&amp;quot; label=&amp;quot;Notifications&amp;quot; width=&amp;quot;75px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;True&amp;quot; value=&amp;quot;True&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;False&amp;quot; value=&amp;quot;False&amp;quot;  default=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode6&amp;quot; label=&amp;quot;Debug&amp;quot; width=&amp;quot;75px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;description&amp;gt;&amp;lt;h2&amp;gt;Debugging&amp;lt;/h2&amp;gt;Select the desired level of debug messaging&amp;lt;/description&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;True&amp;quot; value=&amp;quot;Debug&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;False&amp;quot; value=&amp;quot;Normal&amp;quot;  default=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
&amp;lt;/plugin&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Definition format details:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Tag&lt;br /&gt;
!Description/Attributes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;plugin&amp;gt;&lt;br /&gt;
|Required.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Attribute&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|key&lt;br /&gt;
|Required.&lt;br /&gt;
Unique identifier for the plugin. Never visible to users this should be short, meaningful and made up of characters A-Z, a-z, 0-9 and -_ only.&lt;br /&gt;
Stored in the ‘Extra’ field in the Hardware.&lt;br /&gt;
Used as the base name for the plugin Python file, e.g. ‘DenonAVR’ maps to /plugins/DenonAVR/plugin.py &lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|Required.&lt;br /&gt;
Meaningful description for plugin.&lt;br /&gt;
Shown in the ‘Type’ drop down on the Hardware page.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Required.&lt;br /&gt;
Plugin version.  Used to compare plugin version against repository version to determine if updates are available.&lt;br /&gt;
|-&lt;br /&gt;
|author&lt;br /&gt;
|Optional.&lt;br /&gt;
Plugin author.  Supplied to Hardware page but not currently shown.&lt;br /&gt;
|-&lt;br /&gt;
|wikilink&lt;br /&gt;
|Optional.&lt;br /&gt;
Link to the plugin usage documentation on the Domoticz wiki.&lt;br /&gt;
Shown on the Hardware page.&lt;br /&gt;
|-&lt;br /&gt;
|externallink&lt;br /&gt;
|Optional.&lt;br /&gt;
Link to an external URL that contains additional information about the device.&lt;br /&gt;
Shown on the Hardware page.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;description&amp;gt;&lt;br /&gt;
|HTML description, contained within &amp;lt;plugin&amp;gt; and &amp;lt;param&amp;gt; tags.&lt;br /&gt;
This is displayed in the Hardware page when configuring a plugin. Embedded HTML tags are allowed and respected. &lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;params&amp;gt;&lt;br /&gt;
|Simple wrapper for param tags. Contained within &amp;lt;plugin&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;param&amp;gt;&lt;br /&gt;
|Parameter definitions, Contained within &amp;lt;params&amp;gt;.&lt;br /&gt;
Parameters are used by the Hardware page during plugin addition and update operations.  These are stored in the Hardware table in the database and are made available to the plugin at runtime.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Attribute&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|field&lt;br /&gt;
|Required.&lt;br /&gt;
Column in the hardware table to store the parameter.&amp;lt;br&amp;gt;&lt;br /&gt;
Valid values:&lt;br /&gt;
&lt;br /&gt;
*SerialPort - used by ‘serial’ transports&lt;br /&gt;
*Address - used by non-serial transports&lt;br /&gt;
*Port - used by non-serial transports&lt;br /&gt;
*Mode1 - General purpose&lt;br /&gt;
*Mode2 - General purpose&lt;br /&gt;
*Mode3 - General purpose&lt;br /&gt;
*Mode4 - General purpose&lt;br /&gt;
*Mode5 - General purpose&lt;br /&gt;
*Mode6 - General purpose&lt;br /&gt;
*Username - Username for authentication&lt;br /&gt;
*Password - Password for authentication&lt;br /&gt;
|-&lt;br /&gt;
|label&lt;br /&gt;
|Required.&lt;br /&gt;
Field label.  Where possible standard labels should be used so that Domoticz can translate them when languages other than English are enabled.&lt;br /&gt;
|-&lt;br /&gt;
|width&lt;br /&gt;
|Optional.&lt;br /&gt;
Width of the field&lt;br /&gt;
|-&lt;br /&gt;
|rows&lt;br /&gt;
|Optional.&lt;br /&gt;
Nb rows of the field&lt;br /&gt;
|-&lt;br /&gt;
|required&lt;br /&gt;
|Optional.&lt;br /&gt;
Marks the field as mandatory and the device will not be added unless a value is provided&lt;br /&gt;
|-&lt;br /&gt;
|default&lt;br /&gt;
|Optional.&lt;br /&gt;
Default value for the field. Ignored when &amp;lt;options&amp;gt; are specified.&lt;br /&gt;
|-&lt;br /&gt;
|password&lt;br /&gt;
|Optional.&lt;br /&gt;
Makes the text unreadable during entry and when hardware page is viewed subsequently. Ignored when &amp;lt;options&amp;gt; are specified.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;options&amp;gt;&lt;br /&gt;
|Simple wrapper for option tags. Contained within &amp;lt;param&amp;gt;. &lt;br /&gt;
Parameter definitions that contain this tag will be shown as drop down menus in the Hardware page.  Available values are defined by the &amp;lt;option&amp;gt; tag.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;option&amp;gt;&lt;br /&gt;
|Instance of a drop down option. Contained within &amp;lt;options&amp;gt;. &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Attribute&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|label&lt;br /&gt;
|Required.&lt;br /&gt;
Text to show in dropdown menu.  Will be translated if a translation exists.&lt;br /&gt;
|-&lt;br /&gt;
|value&lt;br /&gt;
|Required.&lt;br /&gt;
Associated value to store in database&lt;br /&gt;
|-&lt;br /&gt;
|default&lt;br /&gt;
|Optional. Valid value:&lt;br /&gt;
true&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Runtime Structure==&lt;br /&gt;
Domoticz exposes settings and device details through four Python dictionaries.&lt;br /&gt;
&lt;br /&gt;
===Settings===&lt;br /&gt;
Contents of the Domoticz Settings page as found in the Preferences database table. These are always available and will be updated if the user changes any settings.  The plugin is not restarted. They can be accessed by name for example: &amp;lt;code&amp;gt;Settings[&amp;quot;Language&amp;quot;]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parameters===&lt;br /&gt;
These are always available and remain static for the lifetime of the plugin.  They can be accessed by name for example: &amp;lt;code&amp;gt;Parameters[&amp;quot;SerialPort&amp;quot;]&amp;lt;/code&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Key&lt;br /&gt;
|Unique short name for the plugin, matches python filename.&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Name assigned by the user to the hardware.&lt;br /&gt;
|-&lt;br /&gt;
|HomeFolder&lt;br /&gt;
|Folder or directory where the plugin was run from.&lt;br /&gt;
|-&lt;br /&gt;
|Author&lt;br /&gt;
|Plugin Author.&lt;br /&gt;
|-&lt;br /&gt;
|Version&lt;br /&gt;
|Plugin version.&lt;br /&gt;
|-&lt;br /&gt;
|Address&lt;br /&gt;
|IP Address, used during connection.&lt;br /&gt;
|-&lt;br /&gt;
|Port&lt;br /&gt;
|IP Port, used during connection.&lt;br /&gt;
|-&lt;br /&gt;
|Username&lt;br /&gt;
|Username.&lt;br /&gt;
|-&lt;br /&gt;
|Password&lt;br /&gt;
|Password.&lt;br /&gt;
|-&lt;br /&gt;
|Mode1&lt;br /&gt;
|General Parameter 1&lt;br /&gt;
|-&lt;br /&gt;
|...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Mode6&lt;br /&gt;
|General Parameter 6&lt;br /&gt;
|-&lt;br /&gt;
|SerialPort&lt;br /&gt;
|SerialPort, used when connecting to Serial Ports.&lt;br /&gt;
|-&lt;br /&gt;
|DomoticzVersion&lt;br /&gt;
|Domoticz version, for instance 4.11774&lt;br /&gt;
|-&lt;br /&gt;
|DomoticzHash&lt;br /&gt;
|Domoticz hash, for instance a06400e05&lt;br /&gt;
|-&lt;br /&gt;
|DomoticzBuildTime&lt;br /&gt;
|Domoticz build time, for instance 2020-03-03 15:41:00&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Extended Plugin Framework===&lt;br /&gt;
&lt;br /&gt;
Available in Domoticz Stable 2022.1!&lt;br /&gt;
&lt;br /&gt;
====Devices====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Members&lt;br /&gt;
|DeviceID.&lt;br /&gt;
Devices are a container class designed to hold the Units that share a common DeviceID&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Access&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|DeviceID&lt;br /&gt;
|Read&lt;br /&gt;
|External device identifier&lt;br /&gt;
|-&lt;br /&gt;
|TimedOut&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Device TimedOut flag. 1=True, 0=False&lt;br /&gt;
|-&lt;br /&gt;
|Units&lt;br /&gt;
|Read&lt;br /&gt;
|Dictionary of Units that have the DeviceID&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Methods&lt;br /&gt;
|Per device calls into Domoticz to manipulate specific devices&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|__init__&lt;br /&gt;
|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|DeviceID&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;The DeviceID to be used with the device. &amp;lt;br&amp;gt;Device objects will be created automatically either during plugin load or when Unit objects are created with new DeviceIDs&amp;lt;br&amp;gt;Field type is Varchar(25)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Refresh&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Refreshes the Device and the Units with the matching DeviceID from the Domoticz database.&lt;br /&gt;
&lt;br /&gt;
Not normally required because device values are updated when callbacks are invoked.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Callbacks&lt;br /&gt;
|If defined, these callbacks will be sent to the Device object rather than to the module level function. Note that the function definitions are different because the API only passes the required parameters so no Device details are passed.&lt;br /&gt;
&lt;br /&gt;
To define these callback plugin authors need to register a local object that extends the Domoticz default.  See the Register function in the [[#C.2B.2B_Callable_API]] section for details&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Callback&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceAdded&lt;br /&gt;
|Parameters: Unit&lt;br /&gt;
Called just after a new device has been added to the hardware, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceAdded is not called when the plugin adds a device.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceModified&lt;br /&gt;
|Parameters: Unit&lt;br /&gt;
Called just after a device owned by the plugin has been modifed, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceModified is not called when the plugin initiated the change e.g. by calling Update.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceDeleted&lt;br /&gt;
|Parameters: Unit&lt;br /&gt;
Called just before a device owned by the plugin is been removed, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceRemoved is not called when the plugin removed the device by calling Delete.&lt;br /&gt;
|-&lt;br /&gt;
|onCommand&lt;br /&gt;
|Parameters: Unit, Command, Level, Hue&lt;br /&gt;
Called by Domoticz in response to a script or Domoticz Web API call sending a command to a Unit in the Device&#039;s Units dictionary&lt;br /&gt;
|-&lt;br /&gt;
|onSecurityEvent&lt;br /&gt;
|Parameters: Level, Description.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import DomoticzEx as Domoticz&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
class hvacDevice(Domoticz.Device):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, DeviceID):&lt;br /&gt;
        super().__init__(DeviceID)&lt;br /&gt;
&lt;br /&gt;
    def onDeviceAdded(self, Unit):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device onDeviceAdded for Unit: &amp;quot;+str(self.Units[Unit]))&lt;br /&gt;
        &lt;br /&gt;
    def onDeviceModified(self, Unit):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device onDeviceModified for Unit: &amp;quot;+str(self.Units[Unit]))&lt;br /&gt;
&lt;br /&gt;
    def onDeviceRemoved(self, Unit):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device onDeviceRemoved for Unit: &amp;quot;+str(self.Units[Unit]))&lt;br /&gt;
&lt;br /&gt;
    def onCommand(self, Unit, Command, Level, Hue):&lt;br /&gt;
        Domoticz.Log(&amp;quot;onCommand called for Device &#039;&amp;quot; + DeviceID + &amp;quot;&#039;, Unit &amp;quot; + str(Unit) + &amp;quot;: Parameter &#039;&amp;quot; + str(Command) + &amp;quot;&#039;, Level: &amp;quot; + str(Level))&lt;br /&gt;
&lt;br /&gt;
        Command = Command.strip()&lt;br /&gt;
        action, sep, params = Command.partition(&#039; &#039;)&lt;br /&gt;
        action = action.capitalize()&lt;br /&gt;
&lt;br /&gt;
# Override the default Domoticz device object with custom one &lt;br /&gt;
Domoticz.Register(Device=hvacDevice)&lt;br /&gt;
&lt;br /&gt;
def onDeviceModified(self, DeviceID, Unit):&lt;br /&gt;
    # This will never be called because the Device specific version overrides it&lt;br /&gt;
    Domoticz.Log(&amp;quot;Device onDeviceModified&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Units====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Members&lt;br /&gt;
|Unit.&lt;br /&gt;
Unit number for the device as specified in the Manifest.&lt;br /&gt;
Note:  Units can be deleted in Domoticz so not all Units specified will necessarily still be present.&lt;br /&gt;
E.g: &amp;lt;code&amp;gt;Domoticz.Log(Devices[&amp;quot;123456&amp;quot;].Units[2].Name)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Access&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|ID&lt;br /&gt;
|Read&lt;br /&gt;
|The Domoticz Device ID&lt;br /&gt;
|-&lt;br /&gt;
|Unit&lt;br /&gt;
|Read&lt;br /&gt;
|The Unit number&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current Name in Domoticz&lt;br /&gt;
|-&lt;br /&gt;
|nValue&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current numeric value&lt;br /&gt;
|-&lt;br /&gt;
|sValue&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current string value&lt;br /&gt;
|-&lt;br /&gt;
|SignalLevel&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Numeric signal level&lt;br /&gt;
|-&lt;br /&gt;
|BatteryLevel&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Numeric battery level&lt;br /&gt;
|-&lt;br /&gt;
|Image&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current image number&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Numeric device type&lt;br /&gt;
|-&lt;br /&gt;
|SubType&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Numeric device subtype&lt;br /&gt;
|-&lt;br /&gt;
|SwitchType&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Numeric device switchtype&lt;br /&gt;
|-&lt;br /&gt;
|Used&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Device Used flag. 1=True, 0=False&lt;br /&gt;
|-&lt;br /&gt;
|Options&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current Device options dictionary&lt;br /&gt;
|-&lt;br /&gt;
|LastLevel&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Last level as reported by Domoticz, used to control sliders on Dimmers and Blinds.&lt;br /&gt;
|-&lt;br /&gt;
|LastUpdate&lt;br /&gt;
|Read&lt;br /&gt;
|Timestamp of the last update, e.g: 2017-01-22 01:21:11&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Description of the device, visible in &amp;quot;Edit&amp;quot; dialog in Domoticz Web UI.&lt;br /&gt;
|-&lt;br /&gt;
|Color&lt;br /&gt;
|Read/Write&lt;br /&gt;
|Current color, see documentation of [[Developing a Python plugin#Callbacks|onCommand callback]] for details on the format.&lt;br /&gt;
|-&lt;br /&gt;
|Adjustment&lt;br /&gt;
|Read&lt;br /&gt;
|Float value representing the adjustment value set for the Unit (via the web UI)&lt;br /&gt;
Note: This is made available to the Plugin author so it can be applied if required, it is not applied by the framework automatically.&lt;br /&gt;
|-&lt;br /&gt;
|Multiplier&lt;br /&gt;
|Read&lt;br /&gt;
|Float value representing the multiplier value set for the Unit (via the web UI).  &lt;br /&gt;
Note: This is made available to the Plugin author so it can be applied if required, it is not applied by the framework automatically.&lt;br /&gt;
|-&lt;br /&gt;
|Parent&lt;br /&gt;
|Read&lt;br /&gt;
|The &#039;owning&#039; Device object&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Methods&lt;br /&gt;
|Per device calls into Domoticz to manipulate specific devices&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
!Example&lt;br /&gt;
|-&lt;br /&gt;
|__init__&lt;br /&gt;
|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Is appended to the Hardware name to set the initial Domoticz Device name.&amp;lt;br&amp;gt;This should not be used in Python because it can be changed in the Web UI.&lt;br /&gt;
|-&lt;br /&gt;
|DeviceID&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Set the DeviceID to be used with the device. Only required to override the default which is and eight digit number dervice from the HardwareID and the Unit number in the format &amp;quot;000H000U&amp;quot;.&amp;lt;br&amp;gt;Field type is Varchar(25)&lt;br /&gt;
|-&lt;br /&gt;
|Unit&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Plugin index for the Device. This can not change and should be used reference Domoticz devices associated with the plugin.  This is also the key for the Devices Dictionary that Domoticz prepopulates for the plugin.&amp;lt;br&amp;gt;Unit numbers must be less than 256.&lt;br /&gt;
|-&lt;br /&gt;
|TypeName&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Common device types, this will set the values for Type, Subtype and Switchtype.&amp;lt;br&amp;gt;See [[#Available_Device_Types]]&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Type value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Subtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Subtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Switchtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Switchtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Image&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Set the image number to be used with the device. Only required to override the default.&amp;lt;br&amp;gt;All images available by JSON API call &amp;quot;/json.htm?type=custom_light_icons&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Options&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Set the Device Options field. A few devices, like Selector Switches, require additional details to be set in this field. It is a Python dictionary consisting of key values pairs, where the keys and values must be strings. See the example to the right.&lt;br /&gt;
|-&lt;br /&gt;
|Used&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
Values&amp;lt;br&amp;gt;&lt;br /&gt;
0 (default) Unused&amp;lt;br&amp;gt;&lt;br /&gt;
1 Used.&amp;lt;br&amp;gt;Set the Device Used field. Used devices appear in the appropriate tab(s), unused devices appear only in the Devices page and must be manually marked as Used.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|Optional&lt;br /&gt;
The description of the Unit&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|Both positional and named parameters are supported.&amp;lt;br&amp;gt;Creates a new Unit object in Python. E.g:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
myUnit1 = DomoticzEx.Unit(&amp;quot;Total&amp;quot;, &amp;quot;000A0001&amp;quot;, 1, 113)&lt;br /&gt;
myUnit2 = DomoticzEx.Unit(Name=&amp;quot;My Counter&amp;quot;, DeviceID=&amp;quot;000A0001&amp;quot;, Unit=2, TypeName=&amp;quot;Counter Incremental&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;or&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import DomoticzEx&lt;br /&gt;
&lt;br /&gt;
def onStart():&lt;br /&gt;
    if (len(Devices) == 0):&lt;br /&gt;
        DomoticzEx.Unit(Name=&amp;quot;Status&amp;quot;, \&lt;br /&gt;
            DeviceID=&amp;quot;myDevice&amp;quot;, Unit=1, \&lt;br /&gt;
            Type=17, Switchtype=17).Create()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;||&lt;br /&gt;
|-&lt;br /&gt;
|Create&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
Successfully created Units are immediately added to the Devices dictionary&lt;br /&gt;
|Creates the Unit in Domoticz from the object. E.g:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
myUnit = DomoticzEx.Unit(Name=&amp;quot;Kilo Watts&amp;quot;, DeviceID=&amp;quot;Power&amp;quot;, Unit=16, TypeName=&amp;quot;kWh&amp;quot;)&lt;br /&gt;
myUnit.Create()&lt;br /&gt;
Domoticz.Log(&amp;quot;Created device: &amp;quot;+Devices[&amp;quot;Power&amp;quot;].Units[16].Name+ \ &lt;br /&gt;
             &amp;quot;, myUnit also still points to the Unit: &amp;quot;+myDev.Name)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;or&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
DomoticzEx.Unit(Name=&amp;quot;Kilo Watts&amp;quot;, DeviceID=&amp;quot;Power&amp;quot;, Unit=16, TypeName=&amp;quot;kWh&amp;quot;).Create()&lt;br /&gt;
Domoticz.Log(&amp;quot;Created device: &amp;quot;+Devices[&amp;quot;Power&amp;quot;].Units[16].Name)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Update&lt;br /&gt;
|Applies the Unit&#039;s current values to the Domoticz database.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Log&lt;br /&gt;
|Optional, Boolean, Default: False&lt;br /&gt;
During the update a row will be written to the log table.&lt;br /&gt;
|-&lt;br /&gt;
|TypeName&lt;br /&gt;
|Optional, String.&amp;lt;br&amp;gt;Common device types, this will set the values for Type, Subtype and Switchtype prior to the database update.&amp;lt;br&amp;gt;See [[#Available_Device_Types]]&lt;br /&gt;
|-&lt;br /&gt;
|UpdateProperties&lt;br /&gt;
|Optional, Boolean, Default: False, from version 2024.4.16100&amp;lt;br&amp;gt;Update db based on unit current Name, SignalLevel, BatteryLevel, Image, Type, Subtype, Switchtype, Used Description and Color members.&lt;br /&gt;
|-&lt;br /&gt;
|UpdateOptions&lt;br /&gt;
|Optional, Boolean, Default: False, from version 2024.4.16100&lt;br /&gt;
&lt;br /&gt;
Update Options in db based on unit current Options member.&lt;br /&gt;
|-&lt;br /&gt;
|SuppressTriggers&lt;br /&gt;
|Optional, Boolean, Default: False, from version 2024.4.16100&lt;br /&gt;
Flag that allows device attributes to be updated without notifications, scene or MQTT, event triggers. nValue and sValue are not written to the database and will be overwritten with current database values.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
If either the nValue or sValues have changed then the update function will signal the event and notification systems (except if SuppressTriggers is True) &lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
Devices[&amp;quot;myDevice&amp;quot;].Units[1].nValue = 42&lt;br /&gt;
Devices[&amp;quot;myDevice&amp;quot;].Units[1].sValue = &amp;quot;Ultimate answer&amp;quot;&lt;br /&gt;
Devices[&amp;quot;myDevice&amp;quot;].Units[1].Update(Log=True)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
Deleted Units are immediately removed from the Devices dictionary but local instances of the object are unchanged.&lt;br /&gt;
|Deletes the device in Domoticz.E.g:&lt;br /&gt;
  Devices[&amp;quot;myDevice&amp;quot;].Units[1].Delete()&lt;br /&gt;
or&lt;br /&gt;
  myDev = Devices[&amp;quot;myDevice&amp;quot;].Units[1]&lt;br /&gt;
  myDev.Delete()&lt;br /&gt;
|-&lt;br /&gt;
|Refresh&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Refreshes the values for the current Unit from the Domoticz database.&lt;br /&gt;
&lt;br /&gt;
Not normally required because Unit values are updated when callbacks are invoked.&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
Devices[&amp;quot;myDevice&amp;quot;].Units[1].Refresh()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Touch&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Updates the Unit&#039;s &#039;last seen&#039; time in the database and nothing else. No events or notifications are triggered as a result of touching a Unit.&lt;br /&gt;
&lt;br /&gt;
After the call the Unit&#039;s LastUpdate field will reflect the new value.&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
Devices[&amp;quot;myDevice&amp;quot;].Units[1].Touch()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Callbacks&lt;br /&gt;
|&lt;br /&gt;
{|&lt;br /&gt;
|If defined, these callbacks will be sent to the Unit object rather than to the Device or module level function.  Note that the function definitions are different because the API only passes the required parameters so no Device or Unit details are passed.&lt;br /&gt;
&lt;br /&gt;
To define these callback plugin authors need to register a local object that extends the Domoticz default.  See the Register function in the [[#C.2B.2B_Callable_API]] section for details&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Callback&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceAdded&lt;br /&gt;
|Parameters: None&lt;br /&gt;
Called just after a new device has been added to the hardware, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceAdded is not called when the plugin adds a device by calling Create.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceModified&lt;br /&gt;
|Parameters: None&lt;br /&gt;
Called just after a device owned by the plugin has been modifed, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceModified is not called when the plugin initiated the change e.g. by calling Update.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceRemoved&lt;br /&gt;
|Parameters: None&lt;br /&gt;
Called just before a device owned by the plugin is removed, for example by a Domoticz Web API call.&lt;br /&gt;
&lt;br /&gt;
onDeviceRemoved is not called when the plugin removed the device by calling Delete.&lt;br /&gt;
|-&lt;br /&gt;
|onCommand&lt;br /&gt;
|Parameters: Command, Level, Hue&lt;br /&gt;
Called by Domoticz in response to a script or Domoticz Web API call sending a command to the Unit&lt;br /&gt;
|-&lt;br /&gt;
|onSecurityEvent&lt;br /&gt;
|Parameters: Level, Description.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import DomoticzEx as Domoticz&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
class hvacDevice(Domoticz.Device):&lt;br /&gt;
    def __init__(self, DeviceID):&lt;br /&gt;
        super().__init__(DeviceID)&lt;br /&gt;
&lt;br /&gt;
    def onDeviceModified(self, Unit):&lt;br /&gt;
        # This will never be called because the Unit specific version overrides it&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device onDeviceModified for Unit: &amp;quot;+str(self.Units[Unit]))&lt;br /&gt;
&lt;br /&gt;
class hvacUnit(Domoticz.Unit):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, Name, DeviceID, Unit, TypeName=&amp;quot;&amp;quot;, Type=0, Subtype=0, Switchtype=0, Image=0, Options=&amp;quot;&amp;quot;, Used=0, Description=&amp;quot;&amp;quot;):&lt;br /&gt;
        super().__init__(Name, DeviceID, Unit, TypeName, Type, Subtype, Switchtype, Image, Options, Used, Description)&lt;br /&gt;
&lt;br /&gt;
    def onDeviceAdded(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Unit onDeviceAdded for &amp;quot;+str(self.Name))&lt;br /&gt;
&lt;br /&gt;
    def onDeviceModified(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Unit onDeviceModified for &amp;quot;+str(self.Name))&lt;br /&gt;
&lt;br /&gt;
    def onDeviceRemoved(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Unit onDeviceRemoved for &amp;quot;+str(self.Name))&lt;br /&gt;
&lt;br /&gt;
    def onCommand(self, Command, Level, Hue):&lt;br /&gt;
        Domoticz.Log(&amp;quot;onCommand called for &#039;&amp;quot; + str(self.Name)+ &amp;quot;&#039;: Parameters &#039;&amp;quot; + str(Command) + &amp;quot;&#039;, Level: &amp;quot; + str(Level))&lt;br /&gt;
&lt;br /&gt;
        Command = Command.strip()&lt;br /&gt;
        action, sep, params = Command.partition(&#039; &#039;)&lt;br /&gt;
        action = action.capitalize()&lt;br /&gt;
&lt;br /&gt;
# Override the default Domoticz objects with custom ones &lt;br /&gt;
Domoticz.Register(Device=hvacDevice, Unit=hvacUnit)&lt;br /&gt;
&lt;br /&gt;
def onDeviceModified(self, DeviceID, Unit):&lt;br /&gt;
    # This will never be called because the Unit specific version overrides it&lt;br /&gt;
    Domoticz.Log(&amp;quot;Device onDeviceModified&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Legacy Plugin Framework===&lt;br /&gt;
====Devices====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Key&lt;br /&gt;
|Unit.&lt;br /&gt;
Unit number for the device as specified in the Manifest.&lt;br /&gt;
Note:  Devices can be deleted in Domoticz so not all Units specified will necessarily still be present.&lt;br /&gt;
E.g: &amp;lt;code&amp;gt;Domoticz.Log(Devices[2].Name)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|ID&lt;br /&gt;
|The Domoticz Device ID&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Current Name in Domoticz&lt;br /&gt;
|-&lt;br /&gt;
|DeviceID&lt;br /&gt;
|External device identifier&lt;br /&gt;
|-&lt;br /&gt;
|nValue&lt;br /&gt;
|Current numeric value&lt;br /&gt;
|-&lt;br /&gt;
|sValue&lt;br /&gt;
|Current string value&lt;br /&gt;
|-&lt;br /&gt;
|SignalLevel&lt;br /&gt;
|Numeric signal level&lt;br /&gt;
|-&lt;br /&gt;
|BatteryLevel&lt;br /&gt;
|Numeric battery level&lt;br /&gt;
|-&lt;br /&gt;
|Image&lt;br /&gt;
|Current image number&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|Numeric device type&lt;br /&gt;
|-&lt;br /&gt;
|SubType&lt;br /&gt;
|Numeric device subtype&lt;br /&gt;
|-&lt;br /&gt;
|SwitchType&lt;br /&gt;
|Numeric device switchtype&lt;br /&gt;
|-&lt;br /&gt;
|Used&lt;br /&gt;
|Device Used flag. 1=True, 0=False&lt;br /&gt;
|-&lt;br /&gt;
|Options&lt;br /&gt;
|Current Device options dictionary&lt;br /&gt;
|-&lt;br /&gt;
|TimedOut&lt;br /&gt;
|Device TimedOut flag. 1=True, 0=False&lt;br /&gt;
|-&lt;br /&gt;
|LastLevel&lt;br /&gt;
|Last level as reported by Domoticz&lt;br /&gt;
|-&lt;br /&gt;
|LastUpdate&lt;br /&gt;
|Timestamp of the last update, e.g: 2017-01-22 01:21:11&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|Description of the device, visible in &amp;quot;Edit&amp;quot; dialog in Domoticz Web UI.&lt;br /&gt;
|-&lt;br /&gt;
|Color&lt;br /&gt;
|Current color, see documentation of [[Developing a Python plugin#Callbacks|onCommand callback]] for details on the format.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Methods&lt;br /&gt;
|Per device calls into Domoticz to manipulate specific devices&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
!Example&lt;br /&gt;
|-&lt;br /&gt;
|__init__&lt;br /&gt;
|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Is appended to the Hardware name to set the initial Domoticz Device name.&amp;lt;br&amp;gt;This should not be used in Python because it can be changed in the Web UI.&lt;br /&gt;
|-&lt;br /&gt;
|Unit&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Plugin index for the Device. This can not change and should be used reference Domoticz devices associated with the plugin.  This is also the key for the Devices Dictionary that Domoticz prepopulates for the plugin.&amp;lt;br&amp;gt;Unit numbers must be less than 256.&lt;br /&gt;
|-&lt;br /&gt;
|TypeName&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Common device types, this will set the values for Type, Subtype and Switchtype.&amp;lt;br&amp;gt;See [[#Available_Device_Types]]&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Type value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Subtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Subtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Switchtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Switchtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Image&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Set the image number to be used with the device. Only required to override the default.&amp;lt;br&amp;gt;All images available by JSON API call &amp;quot;/json.htm?type=custom_light_icons&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Options&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Set the Device Options field. A few devices, like Selector Switches, require additional details to be set in this field. It is a Python dictionary consisting of key values pairs, where the keys and values must be strings. See the example to the right.&lt;br /&gt;
|-&lt;br /&gt;
|Used&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
Values&amp;lt;br&amp;gt;&lt;br /&gt;
0 (default) Unused&amp;lt;br&amp;gt;&lt;br /&gt;
1 Used.&amp;lt;br&amp;gt;Set the Device Used field. Used devices appear in the appropriate tab(s), unused devices appear only in the Devices page and must be manually marked as Used.&lt;br /&gt;
|-&lt;br /&gt;
|DeviceID&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Set the DeviceID to be used with the device. Only required to override the default which is and eight digit number dervice from the HardwareID and the Unit number in the format &amp;quot;000H000U&amp;quot;.&amp;lt;br&amp;gt;Field type is Varchar(25)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|Both positional and named parameters are supported.&amp;lt;br&amp;gt;Creates a new device object in Python. E.g:&lt;br /&gt;
  myDev1 = Domoticz.Device(&amp;quot;Total&amp;quot;, 1, 113)&lt;br /&gt;
  myDev2 = Domoticz.Device(Name=&amp;quot;My Counter&amp;quot;, Unit=2, TypeName=&amp;quot;Counter Incremental&amp;quot;)&lt;br /&gt;
or&lt;br /&gt;
  import Domoticz&lt;br /&gt;
  #&lt;br /&gt;
  def onStart():&lt;br /&gt;
    if (len(Devices) == 0):&lt;br /&gt;
        Domoticz.Device(Name=&amp;quot;Status&amp;quot;,  Unit=1, Type=17,  Switchtype=17).Create()&lt;br /&gt;
Options = {&amp;quot;LevelActions&amp;quot;: &amp;quot;|| ||&amp;quot;,&lt;br /&gt;
                   &amp;quot;LevelNames&amp;quot;: &amp;quot;Off|Video|Music|TV Shows|Live TV&amp;quot;,&lt;br /&gt;
                   &amp;quot;LevelOffHidden&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
                   &amp;quot;SelectorStyle&amp;quot;: &amp;quot;1&amp;quot;}&lt;br /&gt;
        Domoticz.Device(Name=&amp;quot;Source&amp;quot;, Unit=2, \&lt;br /&gt;
                        TypeName=&amp;quot;Selector Switch&amp;quot;, Options=Options).Create()&lt;br /&gt;
        Domoticz.Device(Name=&amp;quot;Volume&amp;quot;, Unit=3, \&lt;br /&gt;
                        Type=244, Subtype=73, Switchtype=7, Image=8).Create()&lt;br /&gt;
        Domoticz.Device(Name=&amp;quot;Playing&amp;quot;, Unit=4, \&lt;br /&gt;
                        Type=244, Subtype=73, Switchtype=7, Image=12).Create()&lt;br /&gt;
        Domoticz.Log(&amp;quot;Devices created.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Device objects in Python are in memory only until they are added to the Domoticz database using the Create function documented below.&lt;br /&gt;
|-&lt;br /&gt;
|Create&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
|Creates the device in Domoticz from the object. E.g:&lt;br /&gt;
  myDev = Domoticz.Device(Name=&amp;quot;Kilo Watts&amp;quot;, Unit=16, TypeName=&amp;quot;kWh&amp;quot;)&lt;br /&gt;
  myDev.Create()&lt;br /&gt;
  Domoticz.Log(&amp;quot;Created device: &amp;quot;+Devices[16].Name+ \&lt;br /&gt;
               &amp;quot;, myDev also points to the Device: &amp;quot;+myDev.Name)&lt;br /&gt;
or&lt;br /&gt;
  Domoticz.Device(Name=&amp;quot;Kilo Watts&amp;quot;, Unit=16, TypeName=&amp;quot;kWh&amp;quot;).Create()&lt;br /&gt;
  Domoticz.Log(&amp;quot;Created device: &amp;quot;+Devices[16].Name)&lt;br /&gt;
Successfully created devices are immediately added to the Devices dictionary.&lt;br /&gt;
|-&lt;br /&gt;
|Update&lt;br /&gt;
|Updates the current values in Domoticz.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|nValue&lt;br /&gt;
|Mandatory.&lt;br /&gt;
The Numerical device value&lt;br /&gt;
|-&lt;br /&gt;
|sValue&lt;br /&gt;
|Mandatory.&lt;br /&gt;
The string device value&lt;br /&gt;
|-&lt;br /&gt;
|Image&lt;br /&gt;
|Optional.&lt;br /&gt;
Numeric custom image number&lt;br /&gt;
|-&lt;br /&gt;
|SignalLevel&lt;br /&gt;
|Optional.&lt;br /&gt;
Device signal strength, default 12&lt;br /&gt;
|-&lt;br /&gt;
|BatteryLevel&lt;br /&gt;
|Optional.&lt;br /&gt;
Device battery strength, default 255&lt;br /&gt;
|-&lt;br /&gt;
|Options&lt;br /&gt;
|Optional.&lt;br /&gt;
Dictionary of device options, default is empty {}&lt;br /&gt;
|-&lt;br /&gt;
|TimedOut&lt;br /&gt;
|Optional.&lt;br /&gt;
Numeric field where 0 (false) is not timed out and other value marks the device as timed out, default is 0.&amp;lt;br /&amp;gt;Timed out devices show with a red header in the Domoticz web UI.&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Is appended to the Hardware name to set the initial Domoticz Device name.&amp;lt;br&amp;gt;This should not be used in Python because it can be changed in the Web UI.&lt;br /&gt;
|-&lt;br /&gt;
|TypeName&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Common device types, this will set the values for Type, Subtype and Switchtype.&amp;lt;br&amp;gt;See [[#Available_Device_Types]]&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Type value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Subtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Subtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Switchtype&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Directly set the numeric Switchtype value. Should only be used if the Device to be created is not supported by TypeName.&lt;br /&gt;
|-&lt;br /&gt;
|Used&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
Values&amp;lt;br&amp;gt;&lt;br /&gt;
0 (default) Unused&amp;lt;br&amp;gt;&lt;br /&gt;
1 Used.&amp;lt;br&amp;gt;Set the Device Used field. Used devices appear in the appropriate tab(s), unused devices appear only in the Devices page and must be manually marked as Used.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Color&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
Current color, see documentation of [[Developing a Python plugin#Callbacks|onCommand callback]] for details on the format.&lt;br /&gt;
|-&lt;br /&gt;
|SuppressTriggers&lt;br /&gt;
|Optional&amp;lt;br&amp;gt;&lt;br /&gt;
Default: False&lt;br /&gt;
Boolean flag that allows device attributes to be updated without notifications, scene or MQTT, event triggers. nValue and sValue are not written to the database and will be overwritten with current database values.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|Both positional and named parameters are supported.&lt;br /&gt;
E.g&lt;br /&gt;
  Devices[1].Update(1,”10”)&lt;br /&gt;
  Devices[Unit].Update(nValue=nValue, sValue=str(sValue), SignalLevel=5, Image=8)&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
|Deletes the device in Domoticz.E.g:&lt;br /&gt;
  Devices[1].Delete()&lt;br /&gt;
or&lt;br /&gt;
  myDev = Devices[2]&lt;br /&gt;
  myDev.Delete()&lt;br /&gt;
Deleted devices are immediately removed from the Devices dictionary but local instances of the object are unchanged.&lt;br /&gt;
|-&lt;br /&gt;
|Refresh&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
|Refreshes the values for the device from the Domoticz database.&lt;br /&gt;
Not normally required because device values are updated when callbacks are invoked.&lt;br /&gt;
|-&lt;br /&gt;
|Touch&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
|Updates the Device&#039;s &#039;last seen&#039; time and nothing else. No events or notifications are triggered as a result of touching a Device.&lt;br /&gt;
After the call the Device&#039;s LastUpdate field will reflect the new value.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Available Device Types===&lt;br /&gt;
&lt;br /&gt;
Filling is in progress, table doesn&#039;t contain full available list yet. Look at the [[Domoticz API/JSON URL&#039;s|Domoticz API/JSON page section Update Devices]] for more background information.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Type&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Subtype&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |TypeName&lt;br /&gt;
! rowspan=&amp;quot;2&amp;quot; |Description&lt;br /&gt;
|-&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|17||Lighting 2|| ||&lt;br /&gt;
| ||Behaves the same as Light/Switch,&amp;lt;br&amp;gt;&#039;&#039;Preferable to use Type 244 instead&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|80||Temp||5||LaCrosse TX3&lt;br /&gt;
|Temperature||Temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
|81||Humidity||1||LaCrosse TX3&lt;br /&gt;
|Humidity||Humidity sensor&lt;br /&gt;
|-&lt;br /&gt;
|82||Temp+Hum||1||LaCrosse TX3&lt;br /&gt;
|Temp+Hum||Temperature + Humidity sensor&lt;br /&gt;
|-&lt;br /&gt;
|84&lt;br /&gt;
|Temp+Hum+Baro&lt;br /&gt;
|1&lt;br /&gt;
|THB1 - BTHR918, BTHGN129&lt;br /&gt;
|Temp+Hum+Baro&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; |Temperature + Humidity + Barometer sensor&amp;lt;br&amp;gt;&lt;br /&gt;
Device.Update(nValue, sValue)&amp;lt;br&amp;gt;&lt;br /&gt;
nValue is always 0,&amp;lt;br&amp;gt;&lt;br /&gt;
sValue is string with values separated by semicolon: Temperature;Humidity;Humidity Status;Barometer;Forecast&amp;lt;br&amp;gt;&lt;br /&gt;
Humidity status: 0 - Normal, 1 - Comfort, 2 - Dry, 3 - Wet&amp;lt;br&amp;gt;&lt;br /&gt;
Forecast: 0 = Heavy Snow, 1 = Snow, 2 = Heavy Rain, 3 = Rain, 4 = Cloudy, 5 = Some Clouds, 6 = Sunny, 7 = Unknown, 8 = Unstable, 9 = Stable&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|2&lt;br /&gt;
|THB2 - BTHR918N, BTHR968&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Weather Station&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|85||Rain||1||&lt;br /&gt;
|Rain||Rain sensor (sValue: &amp;quot;&amp;lt;RainLastHour_mm*100&amp;gt;;&amp;lt;Rain_mm&amp;gt;&amp;quot;, Rain_mm is everincreasing counter)&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |86||Wind||1||&lt;br /&gt;
|Wind||Wind sensor (sValue: &amp;quot;&amp;lt;WindDirDegrees&amp;gt;;&amp;lt;WindDirText&amp;gt;;&amp;lt;WindAveMeterPerSecond*10&amp;gt;;&amp;lt;WindGustMeterPerSecond*10&amp;gt;;&amp;lt;Temp_c&amp;gt;;&amp;lt;WindChill_c&amp;gt;&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|4&lt;br /&gt;
|&lt;br /&gt;
|Wind+Temp+Chill&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|87||UV||1||&lt;br /&gt;
|UV||UV sensor (sValue: &amp;quot;&amp;lt;UV&amp;gt;;&amp;lt;Temp&amp;gt;&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
|89||Current||1||&lt;br /&gt;
|Current/Ampere||Ampere (3 Phase)&lt;br /&gt;
|-&lt;br /&gt;
|93||Scale||1||Weight&lt;br /&gt;
| ||&lt;br /&gt;
|-&lt;br /&gt;
|113||Counter||0||&lt;br /&gt;
| ||RFXMeter&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Additional attribute Switchtype is applicable&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|Energy&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Gas&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Water&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Counter&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Energy Generated&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|Time&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|241&lt;br /&gt;
|Color Switch&lt;br /&gt;
|1&lt;br /&gt;
|RGBW&lt;br /&gt;
|WW&lt;br /&gt;
|RGB + white, either RGB or white can be lit&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;6&amp;quot; |&lt;br /&gt;
| rowspan=&amp;quot;6&amp;quot; |&lt;br /&gt;
|2&lt;br /&gt;
|RGB&lt;br /&gt;
|RGB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|White&lt;br /&gt;
|White&lt;br /&gt;
|Monochrome white&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|RGBWW&lt;br /&gt;
|RGB_CW_WW&lt;br /&gt;
|RGB + cold white + warm white, either RGB or white can be lit&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|RGBWZ&lt;br /&gt;
|RGB_W_Z&lt;br /&gt;
|Like RGBW, but allows combining RGB and white&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|RGBWWZ&lt;br /&gt;
|RGB_CW_WW_Z&lt;br /&gt;
|Like RGBWW, but allows combining RGB and white&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|Cold white + Warm white&lt;br /&gt;
|CW_WW&lt;br /&gt;
|&lt;br /&gt;
|- &lt;br /&gt;
|242||Thermostat (beta 2023.2: Setpoint)||1||Setpoint&lt;br /&gt;
|Set Point||from Beta 2023/2 dd18-9-2023: name change to Setpoint and added Options.&lt;br /&gt;
Options={&#039;ValueStep&#039;:&#039;0.5&#039;, &#039; ValueMin&#039;:&#039;-200&#039;, &#039;ValueMax&#039;:&#039;200&#039;, &#039;ValueUnit&#039;:&#039;°C&#039;}&lt;br /&gt;
|-&lt;br /&gt;
|243&lt;br /&gt;
|General&lt;br /&gt;
|1&lt;br /&gt;
|Visibility&lt;br /&gt;
|Visibility&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;18&amp;quot; |&lt;br /&gt;
| rowspan=&amp;quot;18&amp;quot; |&lt;br /&gt;
|2&lt;br /&gt;
|Solar Radiation&lt;br /&gt;
|Solar Radiation&lt;br /&gt;
|sValue: &amp;quot;float&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|3||Soil Moisture&lt;br /&gt;
|Soil Moisture||&lt;br /&gt;
|-&lt;br /&gt;
|4||Leaf Wetness&lt;br /&gt;
|Leaf Wetness||&lt;br /&gt;
|-&lt;br /&gt;
|6||Percentage&lt;br /&gt;
|Percentage||&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|Fan&lt;br /&gt;
|Fan&lt;br /&gt;
|Fan speed in rpm (from version 2024.3.16011)&lt;br /&gt;
|-&lt;br /&gt;
|8||Voltage&lt;br /&gt;
|Voltage||&lt;br /&gt;
|-&lt;br /&gt;
|9||Pressure&lt;br /&gt;
|Pressure||&lt;br /&gt;
|-&lt;br /&gt;
|19||Text&lt;br /&gt;
|Text||&lt;br /&gt;
|-&lt;br /&gt;
|22||Alert&lt;br /&gt;
|Alert||&lt;br /&gt;
|-&lt;br /&gt;
|23||Ampere (1 Phase)&lt;br /&gt;
|Current (Single)||&lt;br /&gt;
|-&lt;br /&gt;
|24||Sound Level&lt;br /&gt;
|Sound Level||&lt;br /&gt;
|-&lt;br /&gt;
|26||Barometer&lt;br /&gt;
|Barometer||nValue: 0, sValue: &amp;quot;pressure;forecast&amp;quot;&amp;lt;br&amp;gt;Forecast:&amp;lt;br&amp;gt;0 - Stable&amp;lt;br&amp;gt;1 - Sunny&amp;lt;br&amp;gt;2 - Cloudy&amp;lt;br&amp;gt;3 - Unstable&amp;lt;br&amp;gt;4 - Thunderstorm&amp;lt;br&amp;gt;5 - Unknown&amp;lt;br&amp;gt;6 - Cloudy/Rain&lt;br /&gt;
|-&lt;br /&gt;
|27||Distance&lt;br /&gt;
|Distance||&lt;br /&gt;
|-&lt;br /&gt;
|28||Counter Incremental&lt;br /&gt;
|Counter Incremental||Incremental counter used to measure energy (used or produced), gas, water. Does not compute the power or flow rate.  nValue=0, sValue=INCREMENT_VALUE  to increase counter by INCREMENT_VALUE, or sValue=NEGATIVE_VALUE to reset the counter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Additional attribute Switchtype is applicable&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|Energy&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Gas&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Water&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Counter&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Energy Generated&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|Time&lt;br /&gt;
|}&lt;br /&gt;
A counter divider parameter can be specified: for example, for water flux meters, it&#039;s possible to set the divider to 1000 in case that the water flux sensor provides 1 pulse every liter, or 100000 if it sends 1 pulse every 0.01 liter.&lt;br /&gt;
&lt;br /&gt;
sValue parameter is float time, so it&#039;s possible for example to set divider to 1000 (1 liter) and update the device for a smaller quantity, for example sValue=0.002 to increase counter for 2 ml.&lt;br /&gt;
|-&lt;br /&gt;
|29||kWh&lt;br /&gt;
|kWh||Electric (Instant+Counter)&amp;lt;br&amp;gt; nValue should be zero&amp;lt;br&amp;gt;&lt;br /&gt;
sValue are two numbers separated by semicolon like &amp;quot;123;123456&amp;quot; The first number is the actual power in Watt, the second number is actual energy in kWh. When the option &amp;quot;EnergyMeterMode&amp;quot; is set to &amp;quot;Calculated&amp;quot;, the second value is ignored&amp;lt;br&amp;gt;&lt;br /&gt;
Optional argument Options can set the EnergyMeterMode.&amp;lt;br&amp;gt;&lt;br /&gt;
Use Options={&#039;EnergyMeterMode&#039;: &#039;1&#039; } to set energyMeterMode to &amp;quot;Calculated&amp;quot;. Default is &amp;quot;From Device&amp;quot;&lt;br /&gt;
&lt;br /&gt;
When creating the device, set Switchtype=4 to get a device exporting energy (instead of importing)&lt;br /&gt;
|-&lt;br /&gt;
|30||Waterflow&lt;br /&gt;
|Waterflow||&lt;br /&gt;
|-&lt;br /&gt;
|31||Custom Sensor&lt;br /&gt;
|Custom||nValue: 0, sValue: &amp;quot;floatValue&amp;quot;, Options: {&#039;Custom&#039;: &#039;1;&amp;lt;axisUnits&amp;gt;&#039;}&lt;br /&gt;
|-&lt;br /&gt;
|33||Managed counter&lt;br /&gt;
| ||nValue is always 0&amp;lt;br&amp;gt;&lt;br /&gt;
sValue must be 2 semicolon separated values to update Dashboard, for instance &amp;quot;123456;78&amp;quot;, 123456 being the absolute counter value, 78 being the usage (Wh). Set counter to -1 if you can&#039;t know the counter absolute value&amp;lt;br&amp;gt;&lt;br /&gt;
sValue must 3 semicolon separated values, the last value being a date (&amp;quot;%Y-%m-%d&amp;quot; format) to update last week/month/year history, for instance &amp;quot;123456;78;2019-09-24&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
sValue must 3 semicolon separated values, the last value being a date a space and a time (&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot; format) to update last days history, for instance &amp;quot;123456;78;2019-10-03 14:55:00&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Additional attribute Switchtype is applicable&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|Energy&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Gas&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Water&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Counter&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Energy Generated&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|Time&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |244&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |Light/Switch&lt;br /&gt;
|62&lt;br /&gt;
|Selector Switch&lt;br /&gt;
|Selector Switch&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |Additional attribute Switchtype is applicable&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!ID&lt;br /&gt;
!Name&lt;br /&gt;
!TypeName&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|On/Off&lt;br /&gt;
|On/Off (from version 2024.3.16011)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|Doorbell&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Contact&lt;br /&gt;
|Contact&lt;br /&gt;
|Statuses:&amp;lt;br&amp;gt;Open: nValue = 1&amp;lt;br&amp;gt;Closed: nValue = 0&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|Blinds&lt;br /&gt;
|Blinds&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|X10 Siren&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|Smoke Detector&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|Dimmer&lt;br /&gt;
|Dimmer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|Motion Sensor&lt;br /&gt;
|Motion&lt;br /&gt;
|Statuses:&amp;lt;br&amp;gt;Motion: nValue = 1&amp;lt;br&amp;gt;Off: nValue = 0&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|Push On Button&lt;br /&gt;
|Push On&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|Push Off Button&lt;br /&gt;
|Push Off&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|Door Contact&lt;br /&gt;
|&lt;br /&gt;
|Statuses:&amp;lt;br&amp;gt;Open: nValue = 1&amp;lt;br&amp;gt;Closed: nValue = 0&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|Dusk Sensor&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|13&lt;br /&gt;
|Blinds Percentage&lt;br /&gt;
|BlindsPercentage&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|Venetian Blinds US&lt;br /&gt;
|VenetianBlindsUS&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Venetian Blinds EU&lt;br /&gt;
|VenetianBlindsEU&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|17&lt;br /&gt;
|Media Player&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|18&lt;br /&gt;
|Selector&lt;br /&gt;
|Selector Switch&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|19&lt;br /&gt;
|Door Lock&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|20&lt;br /&gt;
|Door Lock Inverted&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|21&lt;br /&gt;
|Blinds Percentage With Stop&lt;br /&gt;
|BlindsPercentageWithStop&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|73&lt;br /&gt;
|Switch&lt;br /&gt;
|Check:&lt;br /&gt;
Additional attribute Switchtype&lt;br /&gt;
|-&lt;br /&gt;
|246||Lux||1||Lux&lt;br /&gt;
|Illumination||Illumination (sValue: &amp;quot;float&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
|247||Temp+Baro||1||LaCrosse TX3&lt;br /&gt;
| ||Temperature + Barometer sensor&lt;br /&gt;
|-&lt;br /&gt;
|248||Usage||1||Electric&lt;br /&gt;
|Usage||&lt;br /&gt;
|-&lt;br /&gt;
|249||Air Quality||1||&lt;br /&gt;
|Air Quality||&lt;br /&gt;
|-&lt;br /&gt;
|250&lt;br /&gt;
|P1 Smart Meter&lt;br /&gt;
|1&lt;br /&gt;
|Energy&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|251&lt;br /&gt;
|P1 Smart Meter&lt;br /&gt;
|2&lt;br /&gt;
|Gas&lt;br /&gt;
|Gas&lt;br /&gt;
|&lt;br /&gt;
|}&amp;lt;br /&amp;gt;&lt;br /&gt;
====Note on counters====&lt;br /&gt;
Usually, counters are updated daily to feed week/month/year history log views. Starting version 4.11774, if you want to disable that behavior to control everything from an external script or a plugin (already the case for managed counter), you can set the &amp;quot;DisableLogAutoUpdate&amp;quot; device option to &amp;quot;true&amp;quot;, for instance in a Python plugin:&lt;br /&gt;
 Domoticz.Device(Name=&amp;quot;MyCounter&amp;quot;, Unit=1, Type=0xfa, Subtype=0x01, Options={&amp;quot;DisableLogAutoUpdate&amp;quot;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;: &amp;quot;true&amp;quot;).Create()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Starting version 4.11774, you can too directly insert data in in history log. Set the &amp;quot;AddDBLogEntry&amp;quot; device option to &amp;quot;true&amp;quot;, for instance in a Python plugin:&lt;br /&gt;
 Domoticz.Device(Name=&amp;quot;MyCounter&amp;quot;, Unit=1, Type=0xfa, Subtype=0x01, Options={&amp;quot;AddDBLogEntry&amp;quot;&amp;lt;span&amp;gt; &amp;lt;/span&amp;gt;: &amp;quot;true&amp;quot;).Create()&lt;br /&gt;
Then, depending on counters, you can insert values in history log. For most counters:&lt;br /&gt;
 Devices[Unit].Update(nValue=nValue, sValue=&amp;quot;COUNTER;USAGE;DATE&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
*COUNTER = absolute counter energy (Wh)&lt;br /&gt;
*USAGE = energy usage in Watt-hours (Wh)&lt;br /&gt;
*DATE = date with %Y-%m-%d format (for instance 2019-09-24) to put data in last week/month/year history log, or &amp;quot;%Y-%m-%d %H:%M:%S&amp;quot; format (for instance 2019-10-03 14:00:00) to put data in last days history log&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For multi meters (P1 Smart Meter, CM113, Electrisave and CM180i):&lt;br /&gt;
 Devices[Unit].Update(nValue=nValue, sValue=&amp;quot;USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD;DATE&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
*USAGE1= energy usage meter tariff 1, This is an incrementing counter&lt;br /&gt;
*USAGE2= energy usage meter tariff 2, This is an incrementing counter&lt;br /&gt;
*RETURN1= energy return meter tariff 1, This is an incrementing counter&lt;br /&gt;
*RETURN2= energy return meter tariff 2, This is an incrementing counter&lt;br /&gt;
*CONS= actual usage power (Watt)&lt;br /&gt;
*PROD= actual return power (Watt)&lt;br /&gt;
*DATE = date with %Y-%m-%d format (for instance 2019-09-24) to put data in last week/month/year history log, or &amp;quot;%Y-%m-%d %H:%M:%S&amp;quot; format (for instance 2019-10-03 14:00:00) to put data in last days history log&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
 Devices[Unit].Update(nValue=nValue, sValue=&amp;quot;USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD;COUNTER1;COUNTER2;COUNTER3;COUNTER4;DATE&amp;quot;)&lt;br /&gt;
as previously, plus absolute counter values&lt;br /&gt;
&lt;br /&gt;
for counters with custom units: Use RFXCom customer counter, e.g.&lt;br /&gt;
Domoticz.Unit(Name=name, Unit=unit, Type=113, Switchtype=3, Options={&amp;quot;ValueQuantity&amp;quot;: &amp;quot;Custom&amp;quot;, &amp;quot;ValueUnits&amp;quot;: &amp;quot;customunit&amp;quot;}).Create()&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Connections===&lt;br /&gt;
Connection objects allow plugin developers to connect to multiple external sources using a variety of transports and protocols simultaneously.  By using the plugin framework to handle connectivity Domoticz will remain responsive no matter how many connections the plugin handles.&amp;lt;br&amp;gt;&lt;br /&gt;
Connections remain active only while they are in scope in Python after that Domoticz will actively disconnect them so plugins should store Connections that they want to keep in global or class variables.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description/Attributes&lt;br /&gt;
|-&lt;br /&gt;
|__init__&lt;br /&gt;
|Defines the connection type that will be used by the object.  &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Required.&amp;lt;br&amp;gt;&lt;br /&gt;
Name of the Connection.  For incoming connections Domoticz will assign a unique name.&lt;br /&gt;
|-&lt;br /&gt;
|Transport&lt;br /&gt;
|Required.&amp;lt;br&amp;gt;&lt;br /&gt;
Valid values:&lt;br /&gt;
&lt;br /&gt;
*TCP/IP: Connect over an IP network then send or receive messages&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/HTTP.py HTTP/HTTPS Client example] that uses GET and POST over HTTP or HTTPS&amp;lt;br /&amp;gt;&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/HTTP%20Listener.py HTTP Listener example] that acts as a lightweight webserver&lt;br /&gt;
&lt;br /&gt;
*TLS/IP: Connect over an IP network using TLS security then send or receive messages&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/HTTP.py HTTP/HTTPS Client example]&lt;br /&gt;
&lt;br /&gt;
*UDP/IP: Send or recieve UDP messages, useful for discovering hardware on a network. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/UDP%20Discovery.py UDP Discovery example]&amp;lt;br /&amp;gt;&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/Kodi.py UDP broadcast example] (onNotification function)&lt;br /&gt;
&lt;br /&gt;
*ICMP/IP: Send or recieve ICMP messages, useful for discovering or pinging hardware on a network.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/domoticz/domoticz/blob/development/plugins/examples/Pinger.py Pinger example]&lt;br /&gt;
&lt;br /&gt;
*Serial: Connect to serial ports, see [https://github.com/domoticz/domoticz/blob/development/plugins/examples/RAVEn.py RAVEn power monitoring example]&lt;br /&gt;
|-&lt;br /&gt;
|Protocol&lt;br /&gt;
|Required.&lt;br /&gt;
The protocol that will be used to talk to the external hardware. This is used to allow Domoticz to break incoming data into single messages to pass to the plugin.&lt;br /&gt;
Valid values:&lt;br /&gt;
&lt;br /&gt;
*None (default)&lt;br /&gt;
*Line&lt;br /&gt;
*JSON&lt;br /&gt;
*XML&lt;br /&gt;
*HTTP&lt;br /&gt;
*HTTPS&lt;br /&gt;
*WS (Web Socket)&lt;br /&gt;
*WSS&lt;br /&gt;
*MQTT&lt;br /&gt;
*MQTTS&lt;br /&gt;
*ICMP&lt;br /&gt;
|-&lt;br /&gt;
|Address&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;TCP/IP or UDP/IP Address or SerialPort to connect to.&lt;br /&gt;
|-&lt;br /&gt;
|Port&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;TCP/IP &amp;amp; UDP/IP connections only, string containing the port number.&lt;br /&gt;
|-&lt;br /&gt;
|Baud&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Serial connections only, the required baud rate.&amp;lt;br&amp;gt;&lt;br /&gt;
Default: 115200&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
This allows Domoticz to make connections on behalf of the plugin.&lt;br /&gt;
E.g: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 myConn = Domoticz.Connection(Name=&amp;quot;JSON Connection&amp;quot;, Transport=&amp;quot;TCP/IP&amp;quot;, Protocol=&amp;quot;JSON&amp;quot;, Address=Parameters[&amp;quot;Address&amp;quot;], Port=Parameters[&amp;quot;Port&amp;quot;])&lt;br /&gt;
 myConn.Connect()&lt;br /&gt;
 secureConn = Domoticz.Connection(Name=&amp;quot;Secure Connection&amp;quot;, Transport=&amp;quot;TCP/IP&amp;quot;, Protocol=&amp;quot;HTTPS&amp;quot;, Address=Parameters[&amp;quot;Address&amp;quot;], Port=&amp;quot;443&amp;quot;)&lt;br /&gt;
 secureConn .Connect()&lt;br /&gt;
 mySerialConn = Domoticz.Connection(Name=&amp;quot;Serial Connection&amp;quot;, Transport=&amp;quot;Serial&amp;quot;, Protocol=&amp;quot;XML&amp;quot;, Address=Parameters[&amp;quot;SerialPort&amp;quot;], Baud=115200)&lt;br /&gt;
 mySerialConn.Connect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Both positional and named parameters are supported. &lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Returns the Name of the Connection.&lt;br /&gt;
|-&lt;br /&gt;
|Address&lt;br /&gt;
|Return/Set the Address associated with the Connection.&lt;br /&gt;
|-&lt;br /&gt;
|Port&lt;br /&gt;
|Return/Set the Port associated with the Connection.&lt;br /&gt;
|-&lt;br /&gt;
|Baud&lt;br /&gt;
|Returns the Baud Rate of the Connection.&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|Get or Set the event target for the Connection. See Target parameter description on Connect and Listen for more detail.&lt;br /&gt;
|-&lt;br /&gt;
|Parent&lt;br /&gt;
|Normally &#039;None&#039; but for incoming connections this will hold the Connection object that is &#039;Listening&#039; for the connection.&lt;br /&gt;
|-&lt;br /&gt;
|Connecting&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Returns True if a connection has been requested but has yet to complete (or fail), otherwise False.&lt;br /&gt;
|-&lt;br /&gt;
|Connected&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Returns True if the connection is connected or listening, otherwise False.&lt;br /&gt;
|-&lt;br /&gt;
|Connect&lt;br /&gt;
|Initiate a connection to a external hardware using transport details.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|Optional.&lt;br /&gt;
A Python object where the Connection&#039;s callbacks should be sent rather than sending them to the module level functions.&lt;br /&gt;
&lt;br /&gt;
Applies to: onConnect, onMessage, onTimeout and onDisconnect.&lt;br /&gt;
&lt;br /&gt;
This functionality is designed to allow plugin authors more flexibility and to segregate connection based code from other callbacks.&lt;br /&gt;
|-&lt;br /&gt;
|Timeout&lt;br /&gt;
|Optional.&lt;br /&gt;
Time in milliseconds to wait for either a connection to occur or data to arrive on a Connection before calling the onTimeout callback.&lt;br /&gt;
&lt;br /&gt;
Applies to Serial, TCP and Secure TCP connections.&lt;br /&gt;
&lt;br /&gt;
Valid values:&lt;br /&gt;
&lt;br /&gt;
0 - No timeout&lt;br /&gt;
&lt;br /&gt;
250 or greater - the milliseconds to wait before queuing an onTimeout event&lt;br /&gt;
|}&lt;br /&gt;
Connect returns immediately and the results of the actual connection operation will be returned via the onConnect callback.  If the address set via the Transport function translates to multiple endpoints they will all be tried in order until the connection succeeds or the list of endpoints is exhausted.&amp;lt;br&amp;gt;&lt;br /&gt;
The Connect operation works with connection based transports.&amp;lt;br&amp;gt;&lt;br /&gt;
Note that I/O operations immediately after a Connect (but before onConnect is called) may fail because the connection is still in progress so is technically not connected.&lt;br /&gt;
|-&lt;br /&gt;
|Listen&lt;br /&gt;
|Start listening on specifed Port using the specified TCP/IP, UDP/IP or ICMP/IP transport.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|Optional.&lt;br /&gt;
A Python object where the Connection&#039;s callbacks should be sent rather than sending them to the module level functions.&lt;br /&gt;
&lt;br /&gt;
Applies to: onConnect, onMessage, onTimeout and onDisconnect.&lt;br /&gt;
&lt;br /&gt;
This functionality is designed to allow plugin authors more flexibility and to segregate connection based code from other callbacks.&lt;br /&gt;
|}&lt;br /&gt;
Connection objects will be created for each client that connects and onConnect will be called.&amp;lt;br&amp;gt;&lt;br /&gt;
If a Listen request is unsuccessful the plugin&#039;s onConnect callback will be called with failure details. If it is successful then onConnect will be called when incoming Connections are made.&lt;br /&gt;
E.g:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 self.httpServerConn = Domoticz.Connection(Name=&amp;quot;WebServer&amp;quot;, Transport=&amp;quot;TCP/IP&amp;quot;, Protocol=&amp;quot;HTTP&amp;quot;, Port=Parameters[&amp;quot;Port&amp;quot;])&lt;br /&gt;
 self.httpServerConn.Listen()&lt;br /&gt;
&lt;br /&gt;
 self.BeaconConn = Domoticz.Connection(Name=&amp;quot;Beacon&amp;quot;, Transport=&amp;quot;UDP/IP&amp;quot;, Address=&amp;quot;239.255.255.250&amp;quot;, Port=&amp;quot;1900&amp;quot;)&lt;br /&gt;
 self.BeaconConn.Listen()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Listening on UDP/IP traffic is normally unicast (point to point) but there are some special cases based on the specified Address:&lt;br /&gt;
&lt;br /&gt;
*Addresses between &amp;quot;224.x.x.x&amp;quot; and &amp;quot;239.x.x.x&amp;quot; will be treated as multicast listeners&lt;br /&gt;
*Address &amp;quot;255.255.255.255&amp;quot; will be treated as a broadcast listener&lt;br /&gt;
|-&lt;br /&gt;
|Send&lt;br /&gt;
|Send the specified message to the external hardware.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Message&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;Message text to send.&amp;lt;br&amp;gt;&lt;br /&gt;
For simple Protocols this can be of type String, ByteArray or Bytes.&amp;lt;br&amp;gt;&lt;br /&gt;
For structured Protocols (such as HTTP) it should be a Dictionary.&lt;br /&gt;
|-&lt;br /&gt;
|Delay&lt;br /&gt;
|Optional.&amp;lt;br&amp;gt;Number of seconds to delay message send.&amp;lt;br&amp;gt;Note that Domoticz will send the message sometime after this period. Other events will be processed in the intervening period so delayed sends will be processed out of order. This feature may be useful during delays when physical devices turn on.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Both positional and named parameters are supported.&amp;lt;br&amp;gt;&lt;br /&gt;
E.g: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 myConn.Send(Message=myMessage, Delay=4)&lt;br /&gt;
&lt;br /&gt;
 Headers = {&amp;quot;Connection&amp;quot;: &amp;quot;keep-alive&amp;quot;, &amp;quot;Accept&amp;quot;: &amp;quot;Content-Type: text/html; charset=UTF-8&amp;quot;}&lt;br /&gt;
 myConn.Send({&amp;quot;Verb&amp;quot;:&amp;quot;GET&amp;quot;, &amp;quot;URL&amp;quot;:&amp;quot;/page.html&amp;quot;, &amp;quot;Headers&amp;quot;: Headers})&lt;br /&gt;
&lt;br /&gt;
 postData = &amp;quot;param1=value&amp;amp;param2=other+value&amp;quot;&lt;br /&gt;
 myHttpConn.Send({&#039;Verb&#039;:&#039;POST&#039;, &#039;URL&#039;:&#039;/MediaRenderer/AVTransport/Control&#039;, &#039;Data&#039;: postData})&lt;br /&gt;
&lt;br /&gt;
 responseData = &amp;quot;&amp;lt;!doctype html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Successful GET!!!&amp;lt;/h1&amp;gt;&amp;lt;body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;&lt;br /&gt;
 self.httpClientConn.Send({&amp;quot;Status&amp;quot;:&amp;quot;200 OK&amp;quot;, &amp;quot;Headers&amp;quot;: {&amp;quot;Connection&amp;quot;: &amp;quot;keep-alive&amp;quot;, &amp;quot;Accept&amp;quot;: &amp;quot;Content-Type: text/html; charset=UTF-8&amp;quot;}, &amp;quot;Data&amp;quot;: responseData })&lt;br /&gt;
&lt;br /&gt;
 udpBcastConn = Domoticz.Connection(Name=&amp;quot;UDP Broadcast Connection&amp;quot;, Transport=&amp;quot;UDP/IP&amp;quot;, Protocol=&amp;quot;None&amp;quot;, Address=&amp;quot;224.0.0.1&amp;quot;, Port=&amp;quot;9777&amp;quot;)&lt;br /&gt;
 udpBcastConn.Send(&amp;quot;Hello World!&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Disconnect&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Terminate the connection to the external hardware for the connection.&amp;lt;br /&amp;gt;&lt;br /&gt;
Disconnect also terminates listening connections for all transports (including connectionless ones e.g UDP/IP).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Images===&lt;br /&gt;
Developers can ship custom images with plugins in the standard Domoticz format as described here: [http://www.domoticz.com/wiki/Custom_icons_for_webinterface#Creating_simple_home_made_icons].  Resultant zip file(s) should be placed in the folder with the plugin itself&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Key&lt;br /&gt;
|Base.&lt;br /&gt;
The base value as specified in icons.txt file in custom image zip file.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|ID&lt;br /&gt;
|Image ID in CustomImages table&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|Name as specified in upload file&lt;br /&gt;
|-&lt;br /&gt;
|Base&lt;br /&gt;
|This MUST start with (or be) the plugin key as defined in the XML definition.  If not the image will not be loaded into the Images dictionary.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|Description as specified in upload file&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Methods&lt;br /&gt;
|Per image calls into Domoticz to manipulate specific images&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|__init__&lt;br /&gt;
|&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Parameter&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Filename&lt;br /&gt;
|Mandatory.&amp;lt;br&amp;gt;The zip file name containing images formatted for Domoticz.&lt;br /&gt;
|}&lt;br /&gt;
|Both positional and named parameters are supported.&amp;lt;br&amp;gt;Creates a new image object in Python.&amp;lt;br&amp;gt;&lt;br /&gt;
E.g To allow users to select from three device icons in the hardware page create three zip files with different bases:&lt;br /&gt;
  myPlugin Icons.zip -&amp;gt; icons.txt&lt;br /&gt;
  &#039;&#039;&#039;myPlugin&#039;&#039;&#039;;Plugin;Plugin Description&lt;br /&gt;
and&lt;br /&gt;
  myPlugin1 Icons.zip -&amp;gt; icons.txt&lt;br /&gt;
  &#039;&#039;&#039;myPluginAlt1&#039;&#039;&#039;;Plugin;Plugin Description&lt;br /&gt;
and&lt;br /&gt;
  myPlugin2 Icons.zip -&amp;gt; icons.txt&lt;br /&gt;
  &#039;&#039;&#039;myPluginAlt2&#039;&#039;&#039;;Plugin;Plugin Description&lt;br /&gt;
and an XML parameter declaration like:&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;plugin key=&amp;quot;&#039;&#039;&#039;myPlugin&#039;&#039;&#039;&amp;quot; name=&amp;quot;myPlugin cool hardware&amp;quot; version=&amp;quot;1.5.0&amp;quot; &amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode1&amp;quot; label=&amp;quot;Icon&amp;quot; width=&amp;quot;100px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Blue&amp;quot;  value=&amp;quot;&amp;lt;nowiki&amp;gt;&#039;&#039;&#039;myPlugin&#039;&#039;&#039;&amp;quot; default=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Black&amp;quot; value=&amp;quot;&#039;&#039;&#039;myPluginAlt1&#039;&#039;&#039;&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;Round&amp;quot; value=&amp;quot;&#039;&#039;&#039;myPluginAlt2&#039;&#039;&#039;&amp;lt;/nowiki&amp;gt;&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
        ...&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
then load the images into Domoticz at startup if they are not there and set the &amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
    def onStart(self):&lt;br /&gt;
        if (&amp;quot;&#039;&#039;&#039;myPlugin&#039;&#039;&#039;&amp;quot;     not in Images):&lt;br /&gt;
            Domoticz.Image(&#039;myPlugin Icons.zip&#039;).Create()&lt;br /&gt;
        if (&amp;quot;&#039;&#039;&#039;myPluginAlt1&#039;&#039;&#039;&amp;quot; not in Images):&lt;br /&gt;
            Domoticz.Image(&#039;myPlugin1 Icons.zip&#039;).Create()&lt;br /&gt;
        if (&amp;quot;&#039;&#039;&#039;myPluginAlt2&#039;&#039;&#039;&amp;quot; not in Images):&lt;br /&gt;
            Domoticz.Image(&#039;myPlugin2 Icons.zip&#039;).Create()&lt;br /&gt;
        &lt;br /&gt;
        if (1 in Devices) and (Parameters[&amp;quot;Mode1&amp;quot;] in Images):&lt;br /&gt;
            if (Devices[1].Image != Images[Parameters[&amp;quot;Mode1&amp;quot;]].ID):&lt;br /&gt;
                Devices[1].Update(nValue=Devices[1].nValue, \ &lt;br /&gt;
                                  sValue=str(Devices[1].sValue), \&lt;br /&gt;
                                  Image=Images[Parameters[&amp;quot;Mode1&amp;quot;]].ID)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Image objects in Python are in memory only until they are added to the Domoticz database using the Create function documented below.&lt;br /&gt;
|-&lt;br /&gt;
|Create&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
|Creates the image in Domoticz from the object. E.g:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  myImg = Domoticz.Image(Filename=&amp;quot;Plugin Icons.zip&amp;quot;)&lt;br /&gt;
  myImg.Create()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  Domoticz.Image(Filename=&amp;quot;Plugin Icons.zip&amp;quot;).Create()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Successfully created images are immediately added to the Images dictionary.&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Parameters: None, acts on current object.&lt;br /&gt;
|Deletes the image in Domoticz.E.g:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  Images[&#039;myPlugin&#039;].Delete()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  myImg = Images[&#039;myPlugin&#039;]&lt;br /&gt;
  myImg.Delete()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Deleted images are immediately removed from the Images dictionary but local instances of the object are unchanged.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Callbacks==&lt;br /&gt;
Plugins are event driven.  If a callback is not used by a plugin then it should &#039;&#039;&#039;not&#039;&#039;&#039; be present in the plugin.py file, Domoticz will not attempt to call callbacks that are not defined.&lt;br /&gt;
&lt;br /&gt;
Domoticz will notify the plugin when certain events occur through a number of callbacks, these are:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Callback&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|onStart&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Called when the hardware is started, either after Domoticz start, hardware creation or update.&lt;br /&gt;
|-&lt;br /&gt;
|onConnect&lt;br /&gt;
|Parameters: Connection, Status, Description&lt;br /&gt;
Called when connection to remote device either succeeds or fails, or when a connection is made to a listening Address:Port. Connection is the Domoticz Connection object associated with the event.  Zero Status indicates success.&lt;br /&gt;
If Status is not zero then the Description will describe the failure.&amp;lt;br&amp;gt;&lt;br /&gt;
This callback is not called for connectionless Transports such as UDP/IP.&lt;br /&gt;
|-&lt;br /&gt;
|onMessage&lt;br /&gt;
|Parameters: Connection, Data.&lt;br /&gt;
Called when a single, complete message is received from the external hardware (as defined by the Protocol setting).&lt;br /&gt;
This callback should be used to interpret messages from the device and set the related Domoticz devices as required.&amp;lt;br&amp;gt;&lt;br /&gt;
Connection is the Domoticz Connection object associated with the event.&amp;lt;br&amp;gt;&lt;br /&gt;
Data is normally a ByteArray except where the Protocol for the Connection has structure (such as HTTP or ICMP), in that case Data will be a Dictionary containing Protocol specific details such as Status and Headers.&lt;br /&gt;
|-&lt;br /&gt;
|onNotification&lt;br /&gt;
|Parameters: Name, Subject, Text, Status, Priority, Sound, ImageFile.&lt;br /&gt;
Called when any Domoticz device generates a notification.  Name parameter is the device that generated the notification, the other parameters contain the notification details.  Hardware that can handle notifications should be notified as required.&lt;br /&gt;
|-&lt;br /&gt;
|onCommand&lt;br /&gt;
|&#039;&#039;&#039;Legacy Plugin Framework (&#039;import Domoticz&#039;)&#039;&#039;&#039;&lt;br /&gt;
*Parameters: Unit, Command, Level, Color&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Extended Plugin Framework (&#039;import DomoticzEx&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Parameters: DeviceID, Unit, Command, Level, Color&lt;br /&gt;
*Can be overidden or Device or Unit objects, see docmentation elsewhere in this page&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Called when a command is received from Domoticz.&lt;br /&gt;
The Unit parameters matches the Unit specified in the device definition and should be used to map commands to Domoticz devices. Level is normally an integer but may be a floating point number if the Unit is linked to a thermostat device.&lt;br /&gt;
This callback should be used to send Domoticz commands to the external hardware.&lt;br /&gt;
The Color parameter is valid if Command is &amp;quot;Set Color&amp;quot; and is a JSON serialized Domoticz color object.&lt;br /&gt;
&lt;br /&gt;
Domoticz color format:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
                      ColorMode {&lt;br /&gt;
                      	ColorModeNone = 0,   // Illegal&lt;br /&gt;
                      	ColorModeWhite = 1,  // White. Valid fields: none&lt;br /&gt;
                      	ColorModeTemp = 2,   // White with color temperature. Valid fields: t&lt;br /&gt;
                      	ColorModeRGB = 3,    // Color. Valid fields: r, g, b.&lt;br /&gt;
                      	ColorModeCustom = 4, // Custom (color + white). Valid fields: r, g, b, cw, ww, depending on device capabilities&lt;br /&gt;
                      	ColorModeLast = ColorModeCustom,&lt;br /&gt;
                      };&lt;br /&gt;
                      &lt;br /&gt;
                      Color {&lt;br /&gt;
                      	ColorMode m;&lt;br /&gt;
                      	uint8_t t;     // Range:0..255, Color temperature (warm / cold ratio, 0 is coldest, 255 is warmest)&lt;br /&gt;
                      	uint8_t r;     // Range:0..255, Red level&lt;br /&gt;
                      	uint8_t g;     // Range:0..255, Green level&lt;br /&gt;
                      	uint8_t b;     // Range:0..255, Blue level&lt;br /&gt;
                      	uint8_t cw;    // Range:0..255, Cold white level&lt;br /&gt;
                      	uint8_t ww;    // Range:0..255, Warm white level (also used as level for monochrome white)&lt;br /&gt;
                      }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|onHeartbeat&lt;br /&gt;
|Called every &#039;heartbeat&#039; seconds (default 10) regardless of connection status.&lt;br /&gt;
Heartbeat interval can be modified by the Heartbeat command: &amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
Domoticz.Heartbeat(30) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; to set the Heartbeat interval to 30s.&lt;br /&gt;
Allows the Plugin to do periodic tasks including request reconnection if the connection has failed.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&#039;&#039;&#039;Warning:&#039;&#039;&#039; Setting this interval to greater than 30 seconds will cause a &#039;thread seems to have ended unexpectedly&#039; message to be written to the log file every 30 seconds. The plugin will function correctly but this message can not be suppressed because it is a standard warning from Domoticz that a piece of hardware may have stopped responding.&amp;lt;br /&amp;gt;If a plugin wants to heartbeat every 100 seconds it should be coded with the heartbeat interval set to 10, 20 or 25 seconds and only take action every 6th, 5th or 4th time the callback is invoked.&lt;br /&gt;
|-&lt;br /&gt;
|onTimeout&lt;br /&gt;
|Parameters: Connection&lt;br /&gt;
Called in response to a connection or read timeout.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Timeout interval set configured for the connection by the &#039;Timeout&#039; parameter optionally specified on the Connect method.&lt;br /&gt;
|-&lt;br /&gt;
|onDisconnect&lt;br /&gt;
|Parameters: Connection&lt;br /&gt;
Called after the remote device is disconnected, Connection is the Domoticz Connection object associated with the event&amp;lt;br&amp;gt;&lt;br /&gt;
This callback is not called for connectionless Transports such as UDP/IP.&lt;br /&gt;
|-&lt;br /&gt;
|onStop&lt;br /&gt;
|Called when the hardware is stopped or deleted from Domoticz.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceAdded&lt;br /&gt;
|&#039;&#039;&#039;Legacy Plugin Framework (&#039;import Domoticz&#039;)&#039;&#039;&#039;&lt;br /&gt;
*Parameters: Unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Extended Plugin Framework (&#039;import DomoticzEx&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Parameters: DeviceID, Unit&lt;br /&gt;
*Can be overidden or Device or Unit objects, see docmentation elsewhere in this page&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Called just after a new device has been added to the hardware, for example by a Domoticz Web API call.&amp;lt;br /&amp;gt;onDeviceAdded is not called when the plugin adds a device&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceModified&lt;br /&gt;
|&#039;&#039;&#039;Legacy Plugin Framework (&#039;import Domoticz&#039;)&#039;&#039;&#039;&lt;br /&gt;
*Parameters: Unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Extended Plugin Framework (&#039;import DomoticzEx&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Parameters: DeviceID, Unit&lt;br /&gt;
*Can be overidden or Device or Unit objects, see docmentation elsewhere in this page&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Called just after a device owned by the plugin has been modifed, for example by a Domoticz Web API call.&amp;lt;br /&amp;gt;onDeviceModified is not called when the plugin initiated the change e.g. by calling Update.&lt;br /&gt;
|-&lt;br /&gt;
|onDeviceRemoved&lt;br /&gt;
|&#039;&#039;&#039;Legacy Plugin Framework (&#039;import Domoticz&#039;)&#039;&#039;&#039;&lt;br /&gt;
*Parameters: Unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Extended Plugin Framework (&#039;import DomoticzEx&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Parameters: DeviceID, Unit&lt;br /&gt;
*Can be overidden or Device or Unit objects, see docmentation elsewhere in this page&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Called just before a device owned by the plugin is been removed, for example by a Domoticz Web API call.&amp;lt;br /&amp;gt;onDeviceRemoved is not called when the plugin removed the device by calling Delete.&lt;br /&gt;
|-&lt;br /&gt;
|onSecurityEvent&lt;br /&gt;
|&#039;&#039;&#039;Legacy Plugin Framework (&#039;import Domoticz&#039;)&#039;&#039;&#039;&lt;br /&gt;
*Parameters: Unit, Level, Description&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Extended Plugin Framework (&#039;import DomoticzEx&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Parameters: DeviceID, Unit, Level, Description&lt;br /&gt;
*Can be overidden or Device or Unit objects, see docmentation elsewhere in this page&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==C++ Callable API==&lt;br /&gt;
Importing the ‘Domoticz’ module in the Python code exposes functions that plugins can call to perform specific functions. All functions are non-blocking and return immediately. &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Function&lt;br /&gt;
!Description/Attributes&lt;br /&gt;
|-&lt;br /&gt;
|Debug&lt;br /&gt;
|Parameters: String&lt;br /&gt;
Write a message to Domoticz log only if verbose logging is turned on.&lt;br /&gt;
|-&lt;br /&gt;
|Log&lt;br /&gt;
|Parameters: String.&lt;br /&gt;
Write a message to Domoticz log&lt;br /&gt;
|-&lt;br /&gt;
|Status&lt;br /&gt;
|Parameters: String.&lt;br /&gt;
Write a status message to Domoticz log&lt;br /&gt;
|-&lt;br /&gt;
|Error&lt;br /&gt;
|Parameters: String&lt;br /&gt;
Write an error message to Domoticz log&lt;br /&gt;
|-&lt;br /&gt;
|Debugging&lt;br /&gt;
|Parameters: Integer.&lt;br /&gt;
Set logging level and type for debugging.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Value&lt;br /&gt;
!Meaning&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|None. All Python and framework debugging is disabled.&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|All. Very verbose log from plugin framework and plugin debug messages.&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|Mask value. Shows messages from Plugin Domoticz.Debug() calls only.&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|Mask Value. Shows high level framework messages only about major the plugin.&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|Mask Value. Shows plugin framework debug messages related to Devices objects.&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Mask Value. Shows plugin framework debug messages related to Connections objects.&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|Mask Value. Shows plugin framework debug messages related to Images objects.&lt;br /&gt;
|-&lt;br /&gt;
|64&lt;br /&gt;
|Mask Value. Dumps contents of inbound and outbound data from Connection objects.&lt;br /&gt;
|-&lt;br /&gt;
|128&lt;br /&gt;
|Mask Value. Shows plugin framework debug messages related to the message queue.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Mask values can be added together, for example to see debugging details around the plugin and its objects use: &amp;lt;code&amp;gt;Domoticz.Debugging(62) # 2+4+8+16+32&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Heartbeat&lt;br /&gt;
|Parameters: Integer (Optional).&lt;br /&gt;
Set the heartbeat interval in seconds if parameter supplied (initial value 10 seconds). &lt;br /&gt;
&lt;br /&gt;
Values greater than 30 seconds will cause a message to be regularly logged about the plugin not responding.  The plugin will actually function correctly with values greater than 30 though.&lt;br /&gt;
&lt;br /&gt;
Returns current Heartbeat value in seconds.&lt;br /&gt;
|-&lt;br /&gt;
|Notifier&lt;br /&gt;
|Parameters: Name, String.&lt;br /&gt;
Informs the plugin framework that the plugin&#039;s external hardware can comsume Domoticz Notifications.&amp;lt;br&amp;gt;&lt;br /&gt;
When the plugin is active the supplied Name will appear as an additional target for Notifications in the standard Domoticz device notification editing page.  The plugin framework will then call the onNotification callback when a notifiable event occurs.&lt;br /&gt;
|-&lt;br /&gt;
|Trace&lt;br /&gt;
|Parameters: N/A, Boolean. Default: False.&lt;br /&gt;
When True, Domoticz will log line numbers of the lines being executed by the plugin. Calling Trace again with False will suppress line level logging. Usage:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  def onHeartBeat():&lt;br /&gt;
    Domoticz.Trace(True)&lt;br /&gt;
    Domoticz.Log(&amp;quot;onHeartBeat called&amp;quot;)&lt;br /&gt;
    ...&lt;br /&gt;
    Domoticz.Trace(False)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Configuration&lt;br /&gt;
|Parameters: Dictionary (Optional).&lt;br /&gt;
Returns a dictionary containing the plugin&#039;s configuration data that was previously stored. If a Dictionary paramater is supplied the database will be updated with the new configuration data.&amp;lt;br&amp;gt;&lt;br /&gt;
Values in the dictionary can be of types: String, Long, Float, Boolean, Bytes, ByteArray, List or Dictionary. Tuples can be specified but will be returned as a List.&amp;lt;br&amp;gt;&lt;br /&gt;
Configuration should not be confused with the Parameters dictionary.  Parameters are set via the Hardware page and are read-only to the plugin, Configuration allows the plugin store structured data in the database rather than writing files or creating Domoticz variables to hold it.&amp;lt;br&amp;gt;&lt;br /&gt;
Usage:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
    # Configuration Helpers&lt;br /&gt;
    def getConfigItem(Key=None, Default={}):&lt;br /&gt;
        Value = Default&lt;br /&gt;
        try:&lt;br /&gt;
            Config = Domoticz.Configuration()&lt;br /&gt;
            if (Key != None):&lt;br /&gt;
                Value = Config[Key] # only return requested key if there was one&lt;br /&gt;
            else:&lt;br /&gt;
                Value = Config      # return the whole configuration if no key&lt;br /&gt;
        except KeyError:&lt;br /&gt;
            Value = Default&lt;br /&gt;
        except Exception as inst:&lt;br /&gt;
            Domoticz.Error(&amp;quot;Domoticz.Configuration read failed: &#039;&amp;quot;+str(inst)+&amp;quot;&#039;&amp;quot;)&lt;br /&gt;
        return Value&lt;br /&gt;
        &lt;br /&gt;
    def setConfigItem(Key=None, Value=None):&lt;br /&gt;
        Config = {}&lt;br /&gt;
        try:&lt;br /&gt;
            Config = Domoticz.Configuration()&lt;br /&gt;
            if (Key != None):&lt;br /&gt;
                Config[Key] = Value&lt;br /&gt;
            else:&lt;br /&gt;
                Config = Value  # set whole configuration if no key specified&lt;br /&gt;
            Config = Domoticz.Configuration(Config)&lt;br /&gt;
        except Exception as inst:&lt;br /&gt;
            Domoticz.Error(&amp;quot;Domoticz.Configuration operation failed: &#039;&amp;quot;+str(inst)+&amp;quot;&#039;&amp;quot;)&lt;br /&gt;
        return Config&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Register&lt;br /&gt;
|Parameters: Device (Class Object), Optional Unit (Class Object)&lt;br /&gt;
Must be positioned outside of any class code so that the Plugin Framework can process it during the module import.&lt;br /&gt;
&lt;br /&gt;
Changes the object type that Domoticz uses to represent Devices (and Units where applicable) to a user defined type.  The specified class must inherit (directly or indirectly) from the default class type and the underlying object initialisation should be invoked (via super().__init__) to ensure there are no unexpected behaviours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The purpose of this function is to support encapsulation and code segregation.&lt;br /&gt;
&lt;br /&gt;
When using the legacy Plugin Framework the following code will cause Domoticz to populate the Devices dictionary with objects of type &#039;myDevice&#039; rather than the default objects of type &#039;Domoticz.Device&#039;:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import Domoticz&lt;br /&gt;
from Domoticz import Device&lt;br /&gt;
&lt;br /&gt;
class myDevice(Domoticz.Device):&lt;br /&gt;
    def __init__(self, Name, Unit, TypeName=&amp;quot;&amp;quot;, Type=0, Subtype=0, Switchtype=0, Image=0, Options=&amp;quot;&amp;quot;, Used=0, DeviceID=&amp;quot;&amp;quot;, Description=&amp;quot;&amp;quot;):&lt;br /&gt;
        super().__init__(Name=Name, Unit=Unit, TypeName=TypeName, Type=Type, Subtype=Subtype, Switchtype=Switchtype, Image=Image, Options=Options, Used=Used, DeviceID=DeviceID, Description=Description)&lt;br /&gt;
        # This code will run prior to onStart for existing data&lt;br /&gt;
        self.localVariable = &amp;quot;Hello&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    def localFunction(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Function called&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # Callbacks cannot be overridden&lt;br /&gt;
&lt;br /&gt;
Domoticz.Register(Device=myDevice)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When using the extended Plugin Framework the following code will cause Domoticz to populate the Devices and Units dictionaries with objects of type &#039;myDevice&#039; and &#039;myUnit&#039; respectively rather than the default objects of type &#039;DomoticzEx.Device&#039; and &#039;DomoticzEx.Unit.  It also shows how to override the class of a particular Unit at run time to a class inherited from the one used in the &#039;Register&#039; call.  A better example of this can be found here: [https://github.com/dnpwwo/Domoticz-DenonEx-Plugin/blob/main/plugin.py Domoticz Denon Plugin] where 3 Unit types are created as sub classes.&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import DomoticzEx as Domoticz&lt;br /&gt;
from DomoticzEx import Device, Unit&lt;br /&gt;
&lt;br /&gt;
class myUnit(Domoticz.Unit):&lt;br /&gt;
    def __init__(self, Name, DeviceID, Unit, TypeName=&amp;quot;&amp;quot;, Type=0, Subtype=0, Switchtype=0, Image=0, Options=&amp;quot;&amp;quot;, Used=0, Description=&amp;quot;&amp;quot;):&lt;br /&gt;
        super().__init__(Name, DeviceID, Unit, TypeName, Type, Subtype, Switchtype, Image, Options, Used, Description)&lt;br /&gt;
        # NOTE: This code will run prior to onStart for existing data&lt;br /&gt;
        self.Refresh()  # Only DeviceID and Unit will be populated this early in the initialisation process so force a refresh&lt;br /&gt;
&lt;br /&gt;
        if (self.SubType == 73) and (self.SwitchType == 0):&lt;br /&gt;
            self.__class__ = myOtherUnit    # Run time polymorphism Python style&lt;br /&gt;
        self.myVar = 0&lt;br /&gt;
&lt;br /&gt;
    # Optionally override onDeviceAdded, onDeviceModified, onDeviceRemoved or onCommand callbacks&lt;br /&gt;
    def onDeviceModified(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Unit onDeviceModified&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    def onCommand(self, Command, Level, Hue):&lt;br /&gt;
        Domoticz.Log(&amp;quot;myUnit onCommand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class myOtherUnit(myUnit):&lt;br /&gt;
&lt;br /&gt;
    # onCommand will be called directly from Domoticz&lt;br /&gt;
    def onCommand(self, Command, Level, Hue):&lt;br /&gt;
        Domoticz.Log(&amp;quot;myOtherUnit onCommand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class myDevice(Domoticz.Device):&lt;br /&gt;
    def __init__(self, DeviceID):&lt;br /&gt;
        super().__init__(DeviceID)&lt;br /&gt;
        # This code will run prior to onStart for existing data&lt;br /&gt;
        self.localVariable = &amp;quot;Hello&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    def localFunction(self):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Function called&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # Optionally override onDeviceAdded, onDeviceModified, onDeviceRemoved or onCommand callbacks&lt;br /&gt;
    def onDeviceModified(self, Unit):&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device onDeviceModified&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Domoticz.Register(Device=myDevice, Unit=myUnit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Dump&lt;br /&gt;
|Parameters: None.&lt;br /&gt;
Dumps current values to the Domoticz log, useful during debugging or exception handling.&lt;br /&gt;
&lt;br /&gt;
Dumped values:&lt;br /&gt;
&lt;br /&gt;
*Current context&lt;br /&gt;
*Local variables&lt;br /&gt;
*Global variables&lt;br /&gt;
&lt;br /&gt;
Example:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import DomoticzEx as Domoticz&lt;br /&gt;
from DomoticzEx import Device, Unit&lt;br /&gt;
import sys&lt;br /&gt;
import datetime&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
modeCoolCmd = &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;C&amp;quot; } } }&#039;&lt;br /&gt;
modeEvapCmd = &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;E&amp;quot; } } }&#039;&lt;br /&gt;
modeHeatCmd = &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;H&amp;quot; } } }&#039;&lt;br /&gt;
&lt;br /&gt;
# Heater, Cooling and Evaporate common functionality&lt;br /&gt;
class hvacBase(Domoticz.Connection):&lt;br /&gt;
    def __init__(self, DeviceID, Name, Image, Address, Port):&lt;br /&gt;
        super().__init__(Name=Name, Transport=&amp;quot;TCP/IP&amp;quot;, Protocol=&amp;quot;None&amp;quot;, Address=Address, Port=Port)&lt;br /&gt;
&lt;br /&gt;
        self.isActive = False&lt;br /&gt;
        self.DeviceID = DeviceID&lt;br /&gt;
        self.DeviceImage = Image&lt;br /&gt;
        self.Device = None&lt;br /&gt;
        self.reportedMode = DeviceID&lt;br /&gt;
&lt;br /&gt;
    def onConnect(self, Connection, Status, Description):&lt;br /&gt;
&lt;br /&gt;
        if (self != Connection):&lt;br /&gt;
            Domoticz.Error(&amp;quot;Connection &#039;&amp;quot;+Connection.Name+&amp;quot;&#039; is not the same as &#039;&amp;quot;+self.Name+&amp;quot;&#039;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        if (Status == 0):&lt;br /&gt;
            Domoticz.Log(self.Name+&amp;quot; connected successfully to: &amp;quot;+Connection.Address+&amp;quot;:&amp;quot;+Connection.Port)&lt;br /&gt;
            for device in Devices:&lt;br /&gt;
                Devices[device].TimedOut = 0&lt;br /&gt;
        else:&lt;br /&gt;
            Domoticz.Log(self.Name+&amp;quot; failed to connect (&amp;quot;+str(Status)+&amp;quot;) to: &amp;quot;+Connection.Address+&amp;quot;:&amp;quot;+Connection.Port)&lt;br /&gt;
            for device in Devices:&lt;br /&gt;
                Devices[device].TimedOut = 1&lt;br /&gt;
&lt;br /&gt;
class Heating(hvacBase):&lt;br /&gt;
    def __init__(self, DeviceID, Name, Image, Address, Port):&lt;br /&gt;
        super().__init__(DeviceID, Name, Image, Address, Port)&lt;br /&gt;
&lt;br /&gt;
    def onMessage(self, Connection, Response):&lt;br /&gt;
        if (len(Response) &amp;gt; 10):    # filter out &#039;HELLO&#039; message&lt;br /&gt;
            self.Disconnect()&lt;br /&gt;
            jsonPayload = json.loads(Response[7:])&lt;br /&gt;
            Domoticz.Dump()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;would dump something like:&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
2021-07-06 15:18:34.296 Rinnai: (Rinnai) Context dump:&lt;br /&gt;
2021-07-06 15:18:34.296 Rinnai: (Rinnai) ----&amp;gt; &#039;Address&#039; &#039;192.168.999.999&#039;&lt;br /&gt;
2021-07-06 15:18:34.297 Rinnai: (Rinnai) ----&amp;gt; &#039;Baud&#039; &#039;-1&#039;&lt;br /&gt;
2021-07-06 15:18:34.297 Rinnai: (Rinnai) ----&amp;gt; &#039;Device&#039; &#039;DeviceID: &#039;HGOM&#039;, Units: 1&#039;&lt;br /&gt;
2021-07-06 15:18:34.298 Rinnai: (Rinnai) ----&amp;gt; &#039;DeviceID&#039; &#039;HGOM&#039;&lt;br /&gt;
2021-07-06 15:18:34.298 Rinnai: (Rinnai) ----&amp;gt; &#039;DeviceImage&#039; &#039;15&#039;&lt;br /&gt;
2021-07-06 15:18:34.298 Rinnai: (Rinnai) ----&amp;gt; &#039;Name&#039; &#039;Heating&#039;&lt;br /&gt;
2021-07-06 15:18:34.299 Rinnai: (Rinnai) ----&amp;gt; &#039;Parent&#039; &#039;None&#039;&lt;br /&gt;
2021-07-06 15:18:34.299 Rinnai: (Rinnai) ----&amp;gt; &#039;Port&#039; &#039;27847&#039;&lt;br /&gt;
2021-07-06 15:18:34.299 Rinnai: (Rinnai) ----&amp;gt; &#039;Target&#039; &#039;Name: &#039;Heating&#039;, Transport: &#039;TCP/IP&#039;, Protocol: &#039;None&#039;, Address: &#039;192.168.999.999&#039;, Port: &#039;27847&#039;, Baud: -1, Timeout: 0, Bytes: 1071, Connected: True, Last Seen: 2021-07-06 15:18:34, Parent: &#039;None&#039;&#039;&lt;br /&gt;
2021-07-06 15:18:34.300 Rinnai: (Rinnai) ----&amp;gt; &#039;isActive&#039; &#039;True&#039;&lt;br /&gt;
2021-07-06 15:18:34.300 Rinnai: (Rinnai) ----&amp;gt; &#039;reportedMode&#039; &#039;HGOM&#039;&lt;br /&gt;
2021-07-06 15:18:34.300 Rinnai: (Rinnai) Locals dump:&lt;br /&gt;
2021-07-06 15:18:34.300 Rinnai: (Rinnai) ----&amp;gt; &#039;self&#039; &#039;Name: &#039;Heating&#039;, Transport: &#039;TCP/IP&#039;, Protocol: &#039;None&#039;, Address: &#039;192.168.999.999&#039;, Port: &#039;27847&#039;, Baud: -1, Timeout: 0, Bytes: 1071, Connected: True, Last Seen: 2021-07-06 15:18:34, Parent: &#039;None&#039;&#039;&lt;br /&gt;
2021-07-06 15:18:34.301 Rinnai: (Rinnai) ----&amp;gt; &#039;Connection&#039; &#039;Name: &#039;Heating&#039;, Transport: &#039;TCP/IP&#039;, Protocol: &#039;None&#039;, Address: &#039;192.168.999.999&#039;, Port: &#039;27847&#039;, Baud: -1, Timeout: 0, Bytes: 1071, Connected: True, Last Seen: 2021-07-06 15:18:34, Parent: &#039;None&#039;&#039;&lt;br /&gt;
2021-07-06 15:18:34.301 Rinnai: (Rinnai) ----&amp;gt; &#039;Response&#039; &#039;b&#039;N000000[{&amp;quot;SYST&amp;quot;: {&amp;quot;CFG&amp;quot;: {&amp;quot;MTSP&amp;quot;: ... &amp;quot;MT&amp;quot;: &amp;quot;231&amp;quot; } } }]&#039;&#039;&lt;br /&gt;
2021-07-06 15:18:34.302 Rinnai: (Rinnai) ----&amp;gt; &#039;jsonPayload&#039; &#039;[{&#039;SYST&#039;: {&#039;CFG&#039;: {&#039;MTSP&#039;: ... &#039;MT&#039;: &#039;231&#039;}}}]&#039;&lt;br /&gt;
2021-07-06 15:18:34.303 Rinnai: (Rinnai) Globals dump:&lt;br /&gt;
2021-07-06 15:18:34.304 Rinnai: (Rinnai) ----&amp;gt; &#039;Domoticz&#039; &#039;&amp;lt;module &#039;DomoticzEx&#039; (built-in)&amp;gt;&#039;&lt;br /&gt;
2021-07-06 15:18:34.304 Rinnai: (Rinnai) ----&amp;gt; &#039;sys&#039; &#039;&amp;lt;module &#039;sys&#039; (built-in)&amp;gt;&#039;&lt;br /&gt;
2021-07-06 15:18:34.304 Rinnai: (Rinnai) ----&amp;gt; &#039;datetime&#039; &#039;&amp;lt;module &#039;datetime&#039; from &#039;C:\\Program Files (x86)\\Python39-32\\Lib\\datetime.py&#039;&amp;gt;&#039;&lt;br /&gt;
2021-07-06 15:18:34.304 Rinnai: (Rinnai) ----&amp;gt; &#039;json&#039; &#039;&amp;lt;module &#039;json&#039; from &#039;C:\\Program Files (x86)\\Python39-32\\Lib\\json\\__init__.py&#039;&amp;gt;&#039;&lt;br /&gt;
2021-07-06 15:18:34.305 Rinnai: (Rinnai) ----&amp;gt; &#039;modeCoolCmd&#039; &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;C&amp;quot; } } }&#039;&lt;br /&gt;
2021-07-06 15:18:34.305 Rinnai: (Rinnai) ----&amp;gt; &#039;modeEvapCmd&#039; &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;E&amp;quot; } } }&#039;&lt;br /&gt;
2021-07-06 15:18:34.306 Rinnai: (Rinnai) ----&amp;gt; &#039;modeHeatCmd&#039; &#039;N000001{&amp;quot;SYST&amp;quot;: {&amp;quot;OSS&amp;quot;: {&amp;quot;MD&amp;quot;: &amp;quot;H&amp;quot; } } }&#039;&lt;br /&gt;
2021-07-06 15:18:34.306 Rinnai: (Rinnai) ----&amp;gt; &#039;_plugin&#039; &#039;&amp;lt;plugin.BasePlugin object at 0x008544E0&amp;gt;&#039;&lt;br /&gt;
2021-07-06 15:18:34.306 Rinnai: (Rinnai) ----&amp;gt; &#039;Parameters&#039; &#039;{&#039;HardwareID&#039;: 2, &#039;HomeFolder&#039;: &#039;plugins\\Domoticz-RinnaiTouch-Plugin\\&#039;, &#039;StartupFolder&#039;: &#039;&#039;, &#039;UserDataFolder&#039;: &#039;&#039;, &#039;WebRoot&#039;: &#039;&#039;, &#039;Database&#039;: &#039;domoticz.db&#039;, &#039;Language&#039;: &#039;en&#039;, &#039;Version&#039;: &#039;1.0.0&#039;, &#039;Author&#039;: &#039;dnpwwo&#039;, &#039;Name&#039;: &#039;Rinnai&#039;, &#039;Address&#039;: &#039;&#039;, &#039;Port&#039;: &#039;27847&#039;, &#039;SerialPort&#039;: &#039;&#039;, &#039;Username&#039;: &#039;&#039;, &#039;Password&#039;: &#039;&#039;, &#039;Key&#039;: &#039;RinnaiTouch&#039;, &#039;Mode1&#039;: &#039;&#039;, &#039;Mode2&#039;: &#039;&#039;, &#039;Mode3&#039;: &#039;&#039;, &#039;Mode4&#039;: &#039;&#039;, &#039;Mode5&#039;: &#039;True&#039;, &#039;Mode6&#039;: &#039;0&#039;, &#039;DomoticzVersion&#039;: &#039;2021.1 (build 2107)&#039;, &#039;DomoticzHash&#039;: &#039;2107&#039;, &#039;DomoticzBuildTime&#039;: &#039;1970-01-01 11:35:07&#039;}&#039;&lt;br /&gt;
2021-07-06 15:18:34.307 Rinnai: (Rinnai) ----&amp;gt; &#039;Devices&#039; &#039;{&#039;HGOM&#039;: &amp;lt;plugin.hvacDevice object at 0x008574E0&amp;gt;, &#039;SYST&#039;: &amp;lt;plugin.hvacDevice object at 0x00857570&amp;gt;}&#039;&lt;br /&gt;
2021-07-06 15:18:34.307 Rinnai: (Rinnai) ----&amp;gt; &#039;Images&#039; &#039;{}&#039;&lt;br /&gt;
2021-07-06 15:18:34.308 Rinnai: (Rinnai) ----&amp;gt; &#039;Settings&#039; &#039;{&#039;DB_Version&#039;: &#039;148&#039;, &#039;Title&#039;: &#039;Domoticz&#039;, &#039;LightHistoryDays&#039;: &#039;30&#039;, ... &#039;MaxElectricPower&#039;: &#039;6000&#039;}&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Protocol Details==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Protocol&lt;br /&gt;
!Details&lt;br /&gt;
|-&lt;br /&gt;
|HTTP/HTTPS&lt;br /&gt;
|HTTP and HTTPS are handled the same from a protocol perspective. HTTPS signals the underlying transport to use SSL/TLS, see [https://www.domoticz.com/wiki/Developing_a_Python_plugin#Connections Connections]. &lt;br /&gt;
The HTTP protocol handles incoming and outgoing messages for both client connections requesting content from remote websites and server side listeners waiting incoming requests.&lt;br /&gt;
Data is passed to the protocol (Connection.Send()) and passed back to the plugin (onMessage) using dictionaries. Key values in these directories are described below with an emphasis on the impact they have to what Domoticz transmits.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Key&lt;br /&gt;
!Details&lt;br /&gt;
|-&lt;br /&gt;
|Verb&lt;br /&gt;
|Any valid HTTP verb (GET, POST etc) although the passed value is not checked but is converted to upper case.&lt;br /&gt;
If this key is present then an HTTP Request will be created and sent&lt;br /&gt;
|-&lt;br /&gt;
|Status&lt;br /&gt;
|String value with the HTTP Response numeric code and text (e.g &#039;200 OK&#039; for success). The value is not checked but sent as is.&lt;br /&gt;
If this key is present then an HTTP Response will be created and sent. Will be ignored if &#039;Verb&#039; was specified.&lt;br /&gt;
|-&lt;br /&gt;
|URL&lt;br /&gt;
|The URL HTTP requests.  Defaults to &amp;quot;/&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Headers&lt;br /&gt;
|A disctionary of headers to inject into the request/response.&lt;br /&gt;
Dictionary keys are header names and values are header values. No processing is done on the headers, they are passed as is but should ideally be capitalised by convention.&amp;lt;br /&amp;gt;&lt;br /&gt;
Header values can be Unicode (string), Bytes, ByteArrays or Lists (for multiple values).&amp;lt;br /&amp;gt;&lt;br /&gt;
Extra headers are conditionally injected when the &#039;Verb&#039; or &#039;Status&#039; key are present:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Header&lt;br /&gt;
!Details&lt;br /&gt;
|-&lt;br /&gt;
|Authorization:Basic&lt;br /&gt;
|If no &#039;Authorization:Basic&#039; header is present for a Request but the Parameters dictionary has Username and Password values then one will be created.&lt;br /&gt;
|-&lt;br /&gt;
|Date&lt;br /&gt;
|If no &#039;Date&#039; header is present for a Response then one will be injected with the value match the current system time.&lt;br /&gt;
|-&lt;br /&gt;
|User-Agent&lt;br /&gt;
|If no &#039;User-Agent&#039; header is present for a Request then one will be injected with the value &#039;Domoticz/1.0&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|Server&lt;br /&gt;
|If no &#039;Server&#039; header is present for a Response then one will be injected with the value &#039;Domoticz/1.0&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|Content-Length&lt;br /&gt;
|If no &#039;Content-Length&#039; header is present then one will be injected with the value matching the length of the supplied Data.&lt;br /&gt;
|-&lt;br /&gt;
|Transfer-Encoding&lt;br /&gt;
|If no &#039;Transfer-Encoding&#039; header is present and &#039;Status&#039; and &#039;Chunk&#039; keys are specified then one will be injected with the value &#039;Chunked&#039;.&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|Data&lt;br /&gt;
|The data to be sent.  This can be a unicode string, bytes or a byte array.&lt;br /&gt;
|-&lt;br /&gt;
|Chunk&lt;br /&gt;
|Used during Responses only, Value is irrelevant.&lt;br /&gt;
Presence of this key informs the framework that this that is a partial HTTP Response using [https://en.wikipedia.org/wiki/Chunked_transfer_encoding chunked transfer encoding]. This encoding is used for large responses to break them up or to return partial data to a client early.&lt;br /&gt;
Sending chunked messages should be be done using a sequence of Send directives like this:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
  myConnection.Send({&#039;Status&#039;:&#039;200 OK&#039;, &#039;Headers&#039;:{&#039;Content-Type&#039;: &#039;text/html&#039;}, &#039;Chunk&#039;:True, &#039;Data&#039;:&#039;This is the first chunk&#039;})&lt;br /&gt;
  myConnection.Send({&#039;Chunk&#039;:True, &#039;Data&#039;:&#039;This is the second chunk&#039;})&lt;br /&gt;
  myConnection.Send({&#039;Chunk&#039;:True, &#039;Data&#039;:&#039;This is the last chunk&#039;}, Delay=1)&lt;br /&gt;
  myConnection.Send({&#039;Chunk&#039;:True}, Delay=1) # this will terminate the response&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Domoticz will send the data as fast as it can so using the &#039;Delay&#039; parameter to slow transmission of large responses can prevent overloading slow clients&lt;br /&gt;
|}&lt;br /&gt;
|-&lt;br /&gt;
|WS/WSS&lt;br /&gt;
|WebSockets (WS) and Secure WebSockets (WSS) are handled the same from a protocol perspective. WSS signals the underlying transport to use SSL/TLS.&lt;br /&gt;
WebSocket connections are initially made over HTTP and then &#039;upgraded&#039; to be Web Sockets.  This means that the message parameters (and matching response) use the protocol details for HTTP until the Server switches to the WebSocket protocol.  Successful upgrades to the WebSocket protocol are signalled by an HTTP response with a &amp;quot;Status&amp;quot; of &amp;quot;101&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
An example WebSockets client plugin can be found in the /plugins/examples folder.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
During the initial post connection message, the following HTTP headers will be injected if they are not supplied but can be overridden:&lt;br /&gt;
&lt;br /&gt;
*Accept (*/*)&lt;br /&gt;
*Accept-Language (en-US,en;q=0.9)&lt;br /&gt;
*Accept-Encoding (gzip, deflate)&lt;br /&gt;
*Connection (keep-alive, Upgrade)&lt;br /&gt;
*Sec-WebSocket-Version (13)&lt;br /&gt;
*Sec-WebSocket-Extensions (permessage-deflate)&lt;br /&gt;
*Upgrade (websocket)&lt;br /&gt;
*User-Agent (Domoticz/1.0)&lt;br /&gt;
*Pragma (no-cache)&lt;br /&gt;
*Cache-Control (no-cache)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
WebSocket servers that the author tested with required values for &#039;Host&#039;, &#039;Origin&#039; and &#039;Sec-WebSocket-Key&#039; in addition to the above list for example:&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
    def onConnect(self, Connection, Status, Description):&lt;br /&gt;
        if Status == 0:&lt;br /&gt;
            Domoticz.Log(&amp;quot;Connected successfully to: &amp;quot; + Connection.Address + &amp;quot;:&amp;quot; + Connection.Port)&lt;br /&gt;
            # End point is now connected so request the upgrade to Web Sockets&lt;br /&gt;
            send_data = {&#039;URL&#039;: Parameters[&amp;quot;Mode1&amp;quot;],&lt;br /&gt;
                         &#039;Headers&#039;: {&#039;Host&#039;: Parameters[&amp;quot;Address&amp;quot;],&lt;br /&gt;
                                     &#039;Origin&#039;: &#039;https://&#039; + Parameters[&amp;quot;Address&amp;quot;],&lt;br /&gt;
                                     &#039;Sec-WebSocket-Key&#039;: base64.b64encode(secrets.token_bytes(16)).decode(&amp;quot;utf-8&amp;quot;)}}&lt;br /&gt;
            Connection.Send(send_data)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Data is passed to the protocol (Connection.Send()) and passed back to the plugin (onMessage) using dictionaries. Key values in these directories are described below.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Key&lt;br /&gt;
!Details&lt;br /&gt;
|-&lt;br /&gt;
|Operation&lt;br /&gt;
|WebSocket control messages, can be sent or recieved.&lt;br /&gt;
Valid Values:  &amp;quot;Ping&amp;quot;, &amp;quot;Pong&amp;quot; and &amp;quot;Close&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Not required (or supplied) for nornal data transfer mesages.&lt;br /&gt;
&lt;br /&gt;
The plugin must respond to incoming &amp;quot;Ping&amp;quot; messages with a &amp;quot;Pong&amp;quot; otherwise the server may terminate the connection.&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
    def onMessage(self, Connection, Data):&lt;br /&gt;
        if &amp;quot;Operation&amp;quot; in Data:  # WebSocket control message&lt;br /&gt;
            if Data[&amp;quot;Operation&amp;quot;] == &amp;quot;Ping&amp;quot;:&lt;br /&gt;
                Connection.Send({&#039;Operation&#039;: &#039;Pong&#039;, &#039;Payload&#039;: &#039;Pong&#039;, &#039;Mask&#039;: secrets.randbits(32)})&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Payload&lt;br /&gt;
|Message data.&lt;br /&gt;
Can be of type String (Text Messages), Bytes or ByteArray (Binary messages).&lt;br /&gt;
|-&lt;br /&gt;
|Mask&lt;br /&gt;
|Data mask for security purposes.&lt;br /&gt;
Technically this is optional but many servers will require it to be specified.&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import secrets&lt;br /&gt;
...&lt;br /&gt;
        if self.websocketConn.Connected():&lt;br /&gt;
            self.websocketConn.Send({&#039;Payload&#039;: &#039;Text message&#039;, &#039;Mask&#039;: secrets.randbits(32)})&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Finish&lt;br /&gt;
|Indicates that this is the final data for a message.&lt;br /&gt;
Domoticz will return each individual message to the plugin but the server may break a large message into several separate messages, when this flag is False the plugin should expect more data in a subsequent onMessage call. &lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==UI==&lt;br /&gt;
There is no built-in capabilities to create UI for plugin but you can use workaround with Domoticz Custom Page&lt;br /&gt;
&lt;br /&gt;
Example of complex UI implementation you can find in [https://github.com/stas-demydiuk/domoticz-zigbee2mqtt-plugin this plugin]&lt;br /&gt;
&lt;br /&gt;
===Setup custom page within plugin===&lt;br /&gt;
&lt;br /&gt;
#Create custom HTML file in your plugins&#039; folder, let&#039;s assume it is index.html&lt;br /&gt;
#General idea is to install custom page when your plugin starts and remove it when plugin stops. To do so you need to modify your plugin&#039;s onStart and onStop methods. Base folder for Python will be Domoticz root (not your plugin root)&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
from shutil import copy2&lt;br /&gt;
import os&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
class Plugin:&lt;br /&gt;
  def onStart(self):&lt;br /&gt;
    ...&lt;br /&gt;
    copy2(&#039;./plugins/myplugin/index.html&#039;, &#039;./www/templates/myplugin.html&#039;)&lt;br /&gt;
&lt;br /&gt;
  def onStop(self):&lt;br /&gt;
    ...&lt;br /&gt;
    if (os.path.exists(&#039;./www/templates/myplugin.html&#039;)):&lt;br /&gt;
      os.remove(&#039;./www/templates/myplugin.html&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Connect your page to Domoticz UI core===&lt;br /&gt;
Domoticz uses AngularJS framework for its UI. Additionally it uses requirejs library for lazy loading. It is not required to follow the same patterns in your custom pages but following them will allow to access built-in classes and components. Every custom page would be loaded and rendered as template for AngularJS framework with access to $rootScope and other global variables.&lt;br /&gt;
&lt;br /&gt;
Example of custom page with access to AngularJS and domoticzApi service:&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!-- Placeholder for page content --&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;plugin-view&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Template for custom component --&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/ng-template&amp;quot; id=&amp;quot;app/myplugin/sampleComponent.html&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;a class=&amp;quot;btnstylerev&amp;quot; back-button&amp;gt;{{ ::&#039;Back&#039; | translate }}&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;h2 class=&amp;quot;page-header&amp;quot;&amp;gt;My Plugin UI&amp;lt;/h2&amp;gt;&lt;br /&gt;
        &amp;lt;p&amp;gt;{{ $ctrl.message }}&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
    require([&#039;app&#039;], function(app) {&lt;br /&gt;
        // Custom component definition&lt;br /&gt;
        app.component(&#039;myPluginRoot&#039;, {&lt;br /&gt;
            templateUrl: &#039;app/myplugin/sampleComponent.html&#039;,&lt;br /&gt;
            controller: function($scope, domoticzApi) {&lt;br /&gt;
                var $ctrl = this;&lt;br /&gt;
                $ctrl.message = &#039;This is my plugin&#039;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        // This piece triggers Angular to re-render page with custom components support&lt;br /&gt;
        angular.element(document).injector().invoke(function($compile) {&lt;br /&gt;
            var $div = angular.element(&#039;&amp;lt;my-plugin-root /&amp;gt;&#039;);&lt;br /&gt;
            angular.element(&#039;#plugin-view&#039;).append($div);&lt;br /&gt;
&lt;br /&gt;
            var scope = angular.element($div).scope();&lt;br /&gt;
            $compile($div)(scope);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
There are a number of examples that are available that show potential usages and patterns that may be useful that can be found [https://github.com/domoticz/domoticz/tree/development/plugins/examples on Github]:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Example&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Base Template&lt;br /&gt;
|A good starting point for developing a plugin.&lt;br /&gt;
|-&lt;br /&gt;
|Denon/Marantz&lt;br /&gt;
|Support for Denon AVR amplifiers.&lt;br /&gt;
&lt;br /&gt;
*TCP/IP connectivity over Telnet using Line protocol.&lt;br /&gt;
*Sending delays when the amplifier is powering on.&lt;br /&gt;
*Dynamic creation of Selector Switches&lt;br /&gt;
*Dynamic discovery using UDP/IP&lt;br /&gt;
|-&lt;br /&gt;
|DLink DSP-W215&lt;br /&gt;
|TCP/IP connectivity using HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
*Features use of SOAP to demonstrate use of HTTP headers&lt;br /&gt;
|-&lt;br /&gt;
|HTTP&lt;br /&gt;
|Shows how to do HTTP connections and handle redirects.&lt;br /&gt;
|-&lt;br /&gt;
|HTTP Listener&lt;br /&gt;
|Shows how to listen for incoming connections.&lt;br /&gt;
&lt;br /&gt;
*Implements a simple webserver and connects to itself.&lt;br /&gt;
|-&lt;br /&gt;
|Kodi&lt;br /&gt;
|Alternate Kodi plugin to the built in one.&lt;br /&gt;
&lt;br /&gt;
*TCP/IP connectivity and use of the JSON protocol.&lt;br /&gt;
*Features three additional devices in Domoticz&lt;br /&gt;
|-&lt;br /&gt;
|RAVEn&lt;br /&gt;
|Alternate RAVEn Energy Monitor plugin to the built in one.&lt;br /&gt;
&lt;br /&gt;
*Serial Port use with the XML protocol&lt;br /&gt;
|-&lt;br /&gt;
|UDP Discovery&lt;br /&gt;
|Logs incoming UDP Broadcast messages for either Dynamic Device Discovery (DDD) or Simple Service Discovery Protocol (SSDP) protocols&lt;br /&gt;
&lt;br /&gt;
*UDP/IP Listening&lt;br /&gt;
|-&lt;br /&gt;
|Mutli-Threaded&lt;br /&gt;
|Starts a Queue on a thread to write log messages and shuts down properly&lt;br /&gt;
|-&lt;br /&gt;
|Web Socket Client&lt;br /&gt;
|Establishes a Web Socket connection and shows how to send and recieve messages&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Importing Modules Fails===&lt;br /&gt;
Python &#039;import&#039; that are unsuccessful will stop the entrie plugin from importing and running unless they are wrapped within a &#039;try&#039;/&#039;except&#039; pair.  If a module is not found the Plugin Framework will provide as much information as it gets from Python.  For example, an attempt to &amp;lt;code&amp;gt;import fakemodule&amp;lt;/code&amp;gt; in a plugin called &#039;Google Devices&#039; will be reported like this in the Domoticz log:&lt;br /&gt;
  2019-03-23 17:17:44.483  Error: (GoogleDevs) failed to load &#039;plugin.py&#039;, Python Path used was &#039;/home/domoticz/plugins/Domoticz-Google-Plugin/:/usr/lib/python36.zip:/usr/lib/python3.6:/usr/lib/python3.6:/usr/lib/python3.6/lib-dynload:/usr/local/lib/python3.6/dist-packages:/usr/lib/python3/dist-packages:/usr/lib/python3.6/dist-packages&#039;.&lt;br /&gt;
  2019-03-23 17:17:44.483  Error: (Google Devices) Module Import failed, exception: &#039;ModuleNotFoundError&#039;&lt;br /&gt;
  2019-03-23 17:17:44.483  Error: (Google Devices) Module Import failed: &#039; Name: fakemodule&#039;&lt;br /&gt;
  2019-03-23 17:17:44.483  Error: (Google Devices) Error Line details not available.&lt;br /&gt;
the framework shows the directories it searches. Broadly these are: the plugin directory, the existing Python path as picked up when Domoticz started and the &#039;site&#039; directories for &#039;&#039;&#039;system level modules&#039;&#039;&#039; installed with pip3. Local &#039;site&#039; directories are not searched by defaul although plugin developers can add any directory the like to the path inside the plugin. Pip3 installs packages in system directories when sudo is used on linux platforms.&lt;br /&gt;
&lt;br /&gt;
===Plugin Crashes Domoticz===&lt;br /&gt;
Yes, this is unfortunately possible. Python3 itself is vulnerable to segmentation faults and Domoticz just inherits this. If you don&#039;t believe me try typing &amp;lt;code&amp;gt;python3 -c &amp;quot;import ctypes; ctypes.string_at(0)&amp;quot;&amp;lt;/code&amp;gt; at a linux command line with Python installed.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
To help troubleshoot these issues the Plugin Framework attempts to load the standard &#039;faulthandler&#039; module for each plugin just before the plugin itself is loaded.  If the plugin triggers any signals a thread by thread stack trace will be printed.  To see this you will need to run Domoticz from the command line or redirect sys.stderr to a file ([https://stackoverflow.com/questions/1956142/how-to-redirect-stderr-in-python how would I do that?])&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Output for a multi-threaded plugin will look something like this, a Python stack trace followed by a normal Domoticz one. The offending line in the plugin is shown in bold:&lt;br /&gt;
    Fatal Python error: Segmentation fault&lt;br /&gt;
    &lt;br /&gt;
    Thread 0xa8d0eb40 (most recent call first):&lt;br /&gt;
      File &amp;quot;/usr/local/lib/python3.6/dist-packages/pychromecast/socket_client.py&amp;quot;, line 361 in run_once&lt;br /&gt;
      File &amp;quot;/usr/local/lib/python3.6/dist-packages/pychromecast/socket_client.py&amp;quot;, line 341 in run&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 916 in _bootstrap_inner&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 884 in _bootstrap&lt;br /&gt;
    &lt;br /&gt;
    Current thread 0xab553b40 (most recent call first):&lt;br /&gt;
    ....&lt;br /&gt;
      File &amp;quot;&amp;lt;frozen importlib._bootstrap&amp;gt;&amp;quot;, line 219 in _call_with_frames_removed&lt;br /&gt;
      File &amp;quot;&amp;lt;frozen importlib._bootstrap_external&amp;gt;&amp;quot;, line 678 in exec_module&lt;br /&gt;
      File &amp;quot;&amp;lt;frozen importlib._bootstrap&amp;gt;&amp;quot;, line 665 in _load_unlocked&lt;br /&gt;
      File &amp;quot;&amp;lt;frozen importlib._bootstrap&amp;gt;&amp;quot;, line 955 in _find_and_load_unlocked&lt;br /&gt;
      File &amp;quot;&amp;lt;frozen importlib._bootstrap&amp;gt;&amp;quot;, line 971 in _find_and_load&lt;br /&gt;
      &#039;&#039;&#039;File &amp;quot;/home/domoticz/plugins/Domoticz-Google-Plugin/plugin.py&amp;quot;, line 322 in handleMessage&#039;&#039;&#039;&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 864 in run&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 916 in _bootstrap_inner&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 884 in _bootstrap&lt;br /&gt;
    &lt;br /&gt;
    Thread 0xad597b40 (most recent call first):&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 299 in wait&lt;br /&gt;
      File &amp;quot;/usr/local/lib/python3.6/dist-packages/zeroconf.py&amp;quot;, line 1794 in wait&lt;br /&gt;
      File &amp;quot;/usr/local/lib/python3.6/dist-packages/zeroconf.py&amp;quot;, line 1365 in run&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 916 in _bootstrap_inner&lt;br /&gt;
      File &amp;quot;/usr/lib/python3.6/threading.py&amp;quot;, line 884 in _bootstrap&lt;br /&gt;
    &lt;br /&gt;
    Thread 0xb57cfb40 (most recent call first):&lt;br /&gt;
    2019-03-23 11:21:04.003  Error: Domoticz(pid:24259, tid:24500(&#039;PluginMgr&#039;)) received fatal signal 11 (Segmentation fault)&lt;br /&gt;
    2019-03-23 11:21:04.003  Error: siginfo address=0x5ec3, address=0xb7f51d09&lt;br /&gt;
    2019-03-23 11:21:04.741  Error: Thread 19 (Thread 0xab553b40 (LWP 24500)):&lt;br /&gt;
    2019-03-23 11:21:04.741  Error: #0  0xb7f51d09 in __kernel_vsyscall ()&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
===Debugging===&lt;br /&gt;
Debugging embedded Python can be done using the standard pdb functionality that comes with Python using the &amp;lt;code&amp;gt;rpdb&amp;lt;/code&amp;gt; (or &#039;Remote PDB&#039;) Python library.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The only restriction is that it can not be done from a debug instance of Domoticz running in Visual Studio on Windows.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Download the &amp;lt;code&amp;gt;rpdb&amp;lt;/code&amp;gt; library from https://pypi.python.org/pypi/rpdb/ and drop the &#039;rpdb&#039; directory into the directory of the plugin to be debugged (or anywhere in the Python path). Alternatively, if pip3 is installed (&amp;lt;code&amp;gt;sudo apt install python3-pip&amp;lt;/code&amp;gt; if on Raspian or a Debian distro) then install the debugger using &amp;lt;code&amp;gt;sudo pip3 install rpdb&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Import the library using something like:&lt;br /&gt;
    def onStart(self):&lt;br /&gt;
        if Parameters[&amp;quot;Mode6&amp;quot;] == &amp;quot;Debug&amp;quot;:&lt;br /&gt;
            Domoticz.Debugging(1)&lt;br /&gt;
            Domoticz.Log(&amp;quot;Debugger started, use &#039;telnet 0.0.0.0 4444&#039; to connect&amp;quot;)&lt;br /&gt;
            import rpdb&lt;br /&gt;
            rpdb.set_trace()&lt;br /&gt;
        else:&lt;br /&gt;
          Domoticz.Log(&amp;quot;onStart called&amp;quot;)&lt;br /&gt;
The &amp;lt;code&amp;gt;rpdb.set_trace()&amp;lt;/code&amp;gt; command causes the Python Framework to be halted and a debugger session to be started on port 4444. For the code above the Domoticz log will show something like:&lt;br /&gt;
  2017-04-17 15:39:25.448  (MyPlugin) Initialized version 1.0.0, author &#039;dnpwwo&#039;&lt;br /&gt;
  2017-04-17 15:39:25.448  (MyPlugin) Debug log level set to: &#039;true&#039;.&lt;br /&gt;
  2017-04-17 15:39:25.448  (MyPlugin) Debugger started, use &#039;telnet 0.0.0.0 4444&#039; to connect&lt;br /&gt;
  pdb is running on 127.0.0.1:4444&lt;br /&gt;
Connect to the debugger using a command line tool such as Telnet. Attaching to the debugger looks like this if you start the session on the same machine as Domoticz, otherwise supply the Domoticz IP address instead of &#039;0.0.0.0&#039;:&lt;br /&gt;
 pi@bob:~$ telnet 0.0.0.0 4444 &lt;br /&gt;
 Trying 0.0.0.0...&lt;br /&gt;
 Connected to 0.0.0.0.&lt;br /&gt;
 Escape character is &#039;^]&#039;.&lt;br /&gt;
 --Return--&lt;br /&gt;
 &amp;gt; /home/pi/domoticz/plugins/MyPlugin/plugin.py(30)onStart()-&amp;gt;None&lt;br /&gt;
 -&amp;gt; rpdb.set_trace()&lt;br /&gt;
 (Pdb)&lt;br /&gt;
enter commands at the prompt such as:&lt;br /&gt;
 (Pdb) l  &lt;br /&gt;
  25  	    def onStart(self):&lt;br /&gt;
  26  	        if Parameters[&amp;quot;Mode6&amp;quot;] == &amp;quot;Debug&amp;quot;:&lt;br /&gt;
  27  	            Domoticz.Debugging(1)&lt;br /&gt;
  28  	            Domoticz.Log(&amp;quot;Debugger started, use &#039;telnet 0.0.0.0 4444&#039; to connect&amp;quot;)&lt;br /&gt;
  29  	            import rpdb&lt;br /&gt;
  30  -&amp;gt;	            rpdb.set_trace()&lt;br /&gt;
  31  	        else:&lt;br /&gt;
  32  	          Domoticz.Log(&amp;quot;onStart called&amp;quot;)&lt;br /&gt;
  33  	&lt;br /&gt;
  34  	    def onStop(self):&lt;br /&gt;
  35  	        Domoticz.Log(&amp;quot;onStop called&amp;quot;)&lt;br /&gt;
 (Pdb) pp Parameters&lt;br /&gt;
  {&#039;Address&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Author&#039;: &#039;dnpwwo&#039;,&lt;br /&gt;
  &#039;HardwareID&#039;: 7,&lt;br /&gt;
  &#039;HomeFolder&#039;: &#039;/home/pi/domoticz/plugins/MyPlugin/&#039;,&lt;br /&gt;
  &#039;Key&#039;: &#039;Debug&#039;,&lt;br /&gt;
  &#039;Mode1&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Mode2&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Mode3&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Mode4&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Mode5&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Mode6&#039;: &#039;Debug&#039;,&lt;br /&gt;
  &#039;Name&#039;: &#039;MyPlugin&#039;,&lt;br /&gt;
  &#039;Password&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Port&#039;: &#039;4444&#039;,&lt;br /&gt;
  &#039;SerialPort&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Username&#039;: &#039;&#039;,&#039;&#039;&lt;br /&gt;
  &#039;Version&#039;: &#039;1.0.0&#039;}&lt;br /&gt;
 (Pdb) b 53&lt;br /&gt;
 Breakpoint 1 at /home/pi/domoticz/plugins/MyPlugin/plugin.py:53&lt;br /&gt;
 (Pdb) continue&lt;br /&gt;
 &amp;gt; /home/pi/domoticz/plugins/MyPlugin/plugin.py(53)onHeartbeat()&lt;br /&gt;
 -&amp;gt; Domoticz.Log(&amp;quot;onHeartbeat called&amp;quot;)&lt;br /&gt;
 (Pdb) ll&lt;br /&gt;
  52  	    def onHeartbeat(self):&lt;br /&gt;
  53 B-&amp;gt;	        Domoticz.Log(&amp;quot;onHeartbeat called&amp;quot;)&lt;br /&gt;
 (Pdb) &lt;br /&gt;
Details of debugging commands can be found here: https://docs.python.org/3/library/pdb.html#debugger-commands&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Domoticz]]&lt;br /&gt;
[[Category:Manual]]&lt;br /&gt;
[[Category:Setup]]&lt;br /&gt;
[[Category:Software]]&lt;br /&gt;
[[Category:Scripting‏‎]]&lt;br /&gt;
[[Category:JSON]]&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Python]]&lt;/div&gt;</summary>
		<author><name>GuillaumeBarberousse</name></author>
	</entry>
	<entry>
		<id>https://wiki.domoticz.com/index.php?title=Mac_OSX&amp;diff=14442</id>
		<title>Mac OSX</title>
		<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Mac_OSX&amp;diff=14442"/>
		<updated>2020-10-03T12:50:55Z</updated>

		<summary type="html">&lt;p&gt;GuillaumeBarberousse: Change loglevel for LaunchAgents to show status and errors&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Purpose of this set is to get Domoticz running on OS X systems.&lt;br /&gt;
(El Capitan Tested)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page explains how to build it from source with Homebrew, you can also get ready to run version from http://www.domoticz.com/downloads/ but note that Z-Wave is NOT included in that version, you have to compile it yourself to use Z-Wave or use the unofficial binary. &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Preparing your OS X for Domoticz=&lt;br /&gt;
&lt;br /&gt;
==Get Xcode command line tools==&lt;br /&gt;
Compiling requires Xcode, which can be installed with command line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
xcode-select --install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It is suggested to installed the Xcode app from the app store (around 3,5 GB). In case you install it, run the app at first once and accept the guarantee terms.&lt;br /&gt;
&amp;lt;br&amp;gt;Prior to Domoticz installation, mac can be prepared alternatively with Homebrew or MacPorts.&amp;lt;br&amp;gt;&lt;br /&gt;
==Homebrew==&lt;br /&gt;
===Homebrew installation===&lt;br /&gt;
Use commande line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ruby -e &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In case you have Homebrew already installed make sure is up to date via command line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
brew update&lt;br /&gt;
brew upgrade&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===X11===&lt;br /&gt;
It is recommended to install X11.app, via XQuartz: [http://xquartz.macosforge.org/landing/]&lt;br /&gt;
&lt;br /&gt;
===Homebrew installation check===&lt;br /&gt;
Prior to install libraries, it is better to check Homebrew installation with command:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
brew doctor&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In case you get the warning:&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;quot;You have an outdated version of /usr/bin/install_name_tool installed. This will cause binary package installations to fail. This can happen if you install osx-gcc-installer or RailsInstaller. To restore it, you must reinstall OS X or restore the binary from the OS packages.&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;do not go ahead until you getit  solved. It can happen that some app/tool had modified the &amp;quot;install_name_tool&amp;quot;. You can find the proper version of &amp;quot;install_name_tool&amp;quot; for OS X Mavericks (working also for Yosemite) on [https://github.com/cinic/install-name-tool]. Just download it and overwrite on folder /usr/bin/. Run again &amp;quot;brew doctor&amp;quot; and warning should disappear. &lt;br /&gt;
&lt;br /&gt;
===Install necessary libraries===&lt;br /&gt;
&lt;br /&gt;
Run following command lines in the terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
brew install cmake&lt;br /&gt;
brew install boost --with-python&lt;br /&gt;
brew install boost-python&lt;br /&gt;
brew install libusb&lt;br /&gt;
brew install libusb-compat&lt;br /&gt;
brew install zlib&lt;br /&gt;
brew install openssl&lt;br /&gt;
brew link openssl --force&lt;br /&gt;
brew install python3&lt;br /&gt;
brew linkapps python3&lt;br /&gt;
brew install lua&lt;br /&gt;
luarocks install luasocket&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
export LDFLAGS=-L/usr/local/opt/openssl/lib&lt;br /&gt;
export CPPFLAGS=-I/usr/local/opt/openssl/include&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Installing the Stable Binary==&lt;br /&gt;
&lt;br /&gt;
Use the Terminal and execute the commands below note that &#039;&#039;&#039;Z-Wave is not included&#039;&#039;&#039; you have to compile that yourself:&lt;br /&gt;
&lt;br /&gt;
 mkdir ~/domoticz&lt;br /&gt;
 cd ~/domoticz&lt;br /&gt;
 curl -O &amp;lt;nowiki&amp;gt;https://releases.domoticz.com/releases/release/domoticz_osx_x86_64.tgz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 tar -zxvf domoticz_osx_x86_64.tgz&lt;br /&gt;
 rm domoticz_osx_x86_64.tgz&lt;br /&gt;
&lt;br /&gt;
continue at section: Make Domoticz startup at boot time (Also needed for Web Update)&lt;br /&gt;
&lt;br /&gt;
==Installing the Beta Binary==&lt;br /&gt;
&lt;br /&gt;
Use the Terminal and execute the commands below note that &#039;&#039;&#039;Z-Wave is not included&#039;&#039;&#039; you have to compile that yourself:&lt;br /&gt;
&lt;br /&gt;
 mkdir ~/domoticz&lt;br /&gt;
 cd ~/domoticz&lt;br /&gt;
 curl -O &amp;lt;nowiki&amp;gt;https://releases.domoticz.com/releases/beta/domoticz_osx_x86_64.tgz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 tar -zxvf domoticz_osx_x86_64.tgz&lt;br /&gt;
 rm domoticz_osx_x86_64.tgz&lt;br /&gt;
&lt;br /&gt;
continue at section: Make Domoticz startup at boot time&lt;br /&gt;
&lt;br /&gt;
==Installing from Source==&lt;br /&gt;
&lt;br /&gt;
Please read carefully!!!&lt;br /&gt;
&lt;br /&gt;
===Download Domoticz source===&lt;br /&gt;
Move to the father folder where you want to install Domoticz and run:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/domoticz/domoticz.git domoticz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Compile OpenZWave===&lt;br /&gt;
You can skip this section about z-wave if you do not use it.&lt;br /&gt;
If you use Z-Wave the brew version is a very old and z-wave is not standard included in domoticz on OSX so you have to compile it to use Z-Wave, compile it in the same &#039;&#039;&#039;root folder&#039;&#039;&#039; as domoticz (thus not inside the domoticz folder).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/OpenZWave/open-zwave.git&lt;br /&gt;
ln -s open-zwave open-zwave-read-only&lt;br /&gt;
cd open-zwave&lt;br /&gt;
make&lt;br /&gt;
make install&lt;br /&gt;
cd ..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Most people make the mistake to clone open-zwave into the domoticz folder. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;DO NOT DO THAT, SERIOUSLY DO NOT DO THAT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Please ensure the SIP protection is disabled on newer OSX (El Capitan, Sierra)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please make sure that your folder look like this in the terminal&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pluto.local:~ Trixwood$ls&lt;br /&gt;
domoticz		open-zwave-read-only&lt;br /&gt;
open-zwave		&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the domoticz and the open-zwave, open-zwave-read-only in the same folder&lt;br /&gt;
&lt;br /&gt;
===Compile Domoticz===&lt;br /&gt;
Before you begin compilling domoticz. &lt;br /&gt;
&lt;br /&gt;
====Speed Up====&lt;br /&gt;
&lt;br /&gt;
Search and replace in main/Scheduler.cpp and in main/SQLHelper.cpp the following: &lt;br /&gt;
 &amp;quot;sleep_seconds(1)&amp;quot; to &amp;quot;sleep_milliseconds(50);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For old systems. If this value is not working for you, try 100 milliseconds or change it back to 1 second.&lt;br /&gt;
&lt;br /&gt;
[https://www.domoticz.com/forum/viewtopic.php?t=11619#p83823]&lt;br /&gt;
&lt;br /&gt;
====LUA Fix====&lt;br /&gt;
Edit lua/src/luaconf.h&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#if defined(LUA_USE_MACOSX)&lt;br /&gt;
#define LUA_USE_POSIX&lt;br /&gt;
#define LUA_USE_DLOPEN      /* does not need -ldl */&lt;br /&gt;
#define LUA_USE_READLINE   /* needs an extra library: -lreadline */&lt;br /&gt;
#define LUA_USE_STRTODHEX   /* assume &#039;strtod&#039; handles hex formats */&lt;br /&gt;
#define LUA_USE_AFORMAT      /* assume &#039;printf&#039; handles &#039;aA&#039; specifiers */&lt;br /&gt;
#define LUA_USE_LONGLONG   /* assume support for long long */&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
removed the #if defines and #endif to force right compiler options...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#define LUA_USE_POSIX&lt;br /&gt;
#define LUA_USE_DLOPEN      /* does not need -ldl */&lt;br /&gt;
#define LUA_USE_READLINE   /* needs an extra library: -lreadline */&lt;br /&gt;
#define LUA_USE_STRTODHEX   /* assume &#039;strtod&#039; handles hex formats */&lt;br /&gt;
#define LUA_USE_AFORMAT      /* assume &#039;printf&#039; handles &#039;aA&#039; specifiers */&lt;br /&gt;
#define LUA_USE_LONGLONG   /* assume support for long long */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://www.domoticz.com/forum/viewtopic.php?f=6&amp;amp;t=11766&amp;amp;p=84568&amp;amp;hilit=compiling#p84566]&lt;br /&gt;
&lt;br /&gt;
====Compile====&lt;br /&gt;
&lt;br /&gt;
Compile domoticz with commands:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd domoticz&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Release  -DPYTHON_INCLUDE_DIR=/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/Headers -DPYTHON_LIBRARY=/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/libpython3.5.dylib CMakeLists.txt&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the Python version installed by Homebrew changes the Python version numbers will need to be adjusted accordingly.  To get a clean version run &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;sudo make install&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
unfortunate it is written to the default /opt/domoticz with root owner so you have to move it and own it&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mv /opt/domoticz ~&lt;br /&gt;
sudo chown -R yourusername:staff ~/domoticz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where yourusername is your user name.&lt;br /&gt;
&lt;br /&gt;
====OpenSSL====&lt;br /&gt;
If you are having problems with openssl, see &lt;br /&gt;
[http://www.domoticz.com/forum/viewtopic.php?f=6&amp;amp;t=2581&amp;amp;p=56799#p56799 forum topic] or this&lt;br /&gt;
[https://www.domoticz.com/forum/viewtopic.php?f=6&amp;amp;t=11766&amp;amp;p=90088#p90088 forum topic]&lt;br /&gt;
&lt;br /&gt;
==Compiling Domoticz with OpenZWave support for MacOS Sierra (10.12)==&lt;br /&gt;
&lt;br /&gt;
===Preparations===&lt;br /&gt;
Follow instructions above for Xcode, Homebrew and X11. Note: if you have compiled openzwave befoe, you’ll see quite a number of warnings when you run &amp;lt;tt&amp;gt;brew doctor&amp;lt;/tt&amp;gt; (notably ’unbrewed’ OpenZWave dylib and header files).&lt;br /&gt;
&lt;br /&gt;
===Installing libraries===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
brew install cmake&lt;br /&gt;
brew install boost&lt;br /&gt;
brew install boost-python&lt;br /&gt;
brew install libusb&lt;br /&gt;
brew install libusb-compat&lt;br /&gt;
brew install openssl&lt;br /&gt;
brew link openssl --force&lt;br /&gt;
brew install python3&lt;br /&gt;
brew linkapps python3&lt;br /&gt;
brew install lua&lt;br /&gt;
luarocks install luasocket&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Installing and linking openssl comes with a number of warnings and caveats which do not prevent you from completing the finalcompilation of Domoticz successfully.&lt;br /&gt;
&lt;br /&gt;
===Download Domoticz and OpenZwave source===&lt;br /&gt;
Move to the folder where you want to create the Domoticz folder (eg within your home directory). &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/domoticz/domoticz.git domoticz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The open-zwave directory has to be created in the same folder (next to the domoticz folder).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/OpenZWave/open-zwave.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Compile OpenZwave===&lt;br /&gt;
Before compiling OpenZWave make sure you disable MacOS’s &#039;&#039;System Integrity Protection&#039;&#039; (SIP) (and to return it to its original state after the compilation is completed). This is only required for OpenZWave. Now compile OpenZwave. Please note you are still required to use &amp;lt;tt&amp;gt;sudo&amp;lt;/tt&amp;gt; for &amp;lt;tt&amp;gt;make install&amp;lt;/tt&amp;gt; even while you have disabled SIP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s open-zwave open-zwave-read-only&lt;br /&gt;
cd open-zwave&lt;br /&gt;
make&lt;br /&gt;
sudo make install&lt;br /&gt;
cd ..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Compile Domoticz===&lt;br /&gt;
You can follow trixwood’s instruction to modify the Domoticz source  above (&amp;lt;tt&amp;gt;sleep&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;LUA&amp;lt;/tt&amp;gt;) but this is not required for a successful compilation. The export statements below replace the original export statements listed above for &amp;lt;tt&amp;gt;LDFLAGS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;CPPFLAGS&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd domoticz&lt;br /&gt;
export OPENSSL_ROOT_DIR=/usr/local/opt/openssl/&lt;br /&gt;
export OPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_INCLUDE_DIR=/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/Headers -DPYTHON_LIBRARY=/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6m.dylib -DUSE_PYTHON_PLUGINS=NO CMakeLists.txt&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note you may have to change the references to the Python folders in the cmake statement depending on your Python version. Simply follow the folders in the Cellar directory to find the correct folders for you.&amp;lt;br&amp;gt;&lt;br /&gt;
Now you should have the domoticz executable in the Domoticz folder.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
MacOS Sierra Instructions above are a summary of a slightly more detailed description posted in the [http://domoticz.com/forum/viewtopic.php?p=118725#p118725 Domoticz forum]&lt;br /&gt;
&lt;br /&gt;
=Domoticz start and stop=&lt;br /&gt;
You can start and stop Domticz via terminal or via script.&lt;br /&gt;
&lt;br /&gt;
==From Terminal==&lt;br /&gt;
This solution will keep terminal busy.&lt;br /&gt;
===Start Domoticz===&lt;br /&gt;
Enter domoticz folder and run:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
./domoticz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The open Safari and go to webpage: http://localhost:8080&lt;br /&gt;
&lt;br /&gt;
===Stop Domoticz===&lt;br /&gt;
From terminal just press ctrl+c&lt;br /&gt;
&lt;br /&gt;
==Make Domoticz startup at boot time==&lt;br /&gt;
Starting and stopping a OSX script/app can best be done by using launchctl&amp;lt;br&amp;gt;&lt;br /&gt;
Create a file named com.domoticz.server.plist in /Library/LaunchAgents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE plist PUBLIC &amp;quot;-//Apple//DTD PLIST 1.0//EN&amp;quot; &amp;quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;dict&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;Disabled&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;false/&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;string&amp;gt;com.domoticz.server&amp;lt;/string&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;ProgramArguments&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;array&amp;gt;&lt;br /&gt;
          &amp;lt;string&amp;gt;/opt/domoticz/domoticz&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;-www&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;8080&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;-log&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;/var/log/domoticz.log&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;-loglevel&amp;lt;/string&amp;gt;&lt;br /&gt;
                &amp;lt;string&amp;gt;normal,status,error&amp;lt;/string&amp;gt;&lt;br /&gt;
        &amp;lt;/array&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;OnDemand&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;false/&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;KeepAlive&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;true/&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;RunAtLoad&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;true/&amp;gt;&lt;br /&gt;
        &amp;lt;key&amp;gt;WorkingDirectory&amp;lt;/key&amp;gt;&lt;br /&gt;
        &amp;lt;string&amp;gt;/opt/domoticz&amp;lt;/string&amp;gt;&lt;br /&gt;
&amp;lt;/dict&amp;gt;&lt;br /&gt;
&amp;lt;/plist&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the launch script with: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
launchctl load /Library/LaunchAgents/com.domoticz.server.plist&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and start it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
launchctl start com.domoticz.server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or use a GUI interface: [http://www.soma-zone.com/LaunchControl/ LaunchControl]&lt;br /&gt;
&lt;br /&gt;
=Not Working=&lt;br /&gt;
These items will not work tested version 3.48-3.52&lt;br /&gt;
&lt;br /&gt;
*[https://www.domoticz.com/forum/viewtopic.php?f=6&amp;amp;t=11766&amp;amp;p=90080#p84564 Updater]&lt;br /&gt;
*[https://www.domoticz.com/forum/viewtopic.php?f=6&amp;amp;t=11766&amp;amp;p=90080#p84568 Motherboard Sensors]&lt;br /&gt;
*System Alive Checker (Ping)&lt;br /&gt;
*[https://www.domoticz.com/wiki/Voltcraft_CO-20 Volcraft CO20 USB]&lt;br /&gt;
&lt;br /&gt;
Also note that using sockets in LUA is broken in the release version, to fix that compile it yourself :-)&lt;br /&gt;
&lt;br /&gt;
=Usefull Links=&lt;br /&gt;
&lt;br /&gt;
===iMessage Notification===&lt;br /&gt;
iMessage Notification [https://www.domoticz.com/forum/viewtopic.php?f=23&amp;amp;t=11870&amp;amp;p=85334#p85334 iMessage]&lt;br /&gt;
&lt;br /&gt;
===Airplay / iTunes===&lt;br /&gt;
&lt;br /&gt;
[https://www.domoticz.com/forum/viewtopic.php?f=38&amp;amp;t=9190]&lt;br /&gt;
&lt;br /&gt;
===Voice Commands: Talk to Domoticz===&lt;br /&gt;
Voice Commands: Talk to Domoticz (offline, make sure you check that box!) [https://support.apple.com/en-us/HT202584 Voice Recognition] [https://support.apple.com/kb/PH21513?viewlocale=en_US&amp;amp;locale=en_NZ Voice Commands]&lt;br /&gt;
&lt;br /&gt;
===Text To Speech (TTS)===&lt;br /&gt;
Text To Speech (TTS) [http://osxdaily.com/2011/07/25/how-to-add-new-voices-to-mac-os-x/ Text To Speech Config] &amp;amp;&lt;br /&gt;
[http://www.techradar.com/how-to/computing/apple/terminal-101-making-your-mac-talk-with-say-1305649 Text To Speech Command Line]&lt;br /&gt;
&lt;br /&gt;
===Camera Motion Detection=== &lt;br /&gt;
Camera Motion Detection: You can split one camera into 4, making it possible to detect walk direction with on cheap usb camera, since it uses applescript you can easily communicate with domoticz&lt;br /&gt;
[http://www.bensoftware.com/securityspy/ SecuritySpy] [bit.ly/1Tw3Vgj .] and for some fine-tunning [https://itunes.apple.com/nl/app/webcam-settings/id533696630?mt=12 Webcam Settings]&lt;br /&gt;
[https://www.domoticz.com/forum/viewtopic.php?f=23&amp;amp;t=11908&amp;amp;p=85624&amp;amp;hilit=walk+direction#p85624 Zone &amp;amp; Walking Direction Motion Sensors]&lt;br /&gt;
&lt;br /&gt;
===Scripts===&lt;br /&gt;
Scripts [https://itunes.apple.com/app/eventscripts/id525319418?mt=12 Event Scripts]&lt;br /&gt;
&lt;br /&gt;
[[Category:Domoticz]]&lt;br /&gt;
[[Category:Manual]]&lt;br /&gt;
[[Category:Install]]&lt;br /&gt;
[[Category:TTS]]&lt;br /&gt;
[[Category:Speech Recognition]]&lt;br /&gt;
[[Category:Z-Wave]]&lt;br /&gt;
[[Category:OSX]]&lt;/div&gt;</summary>
		<author><name>GuillaumeBarberousse</name></author>
	</entry>
</feed>