You can find an empty plugin database here
Here is its structure: first a folder with the name of your plugin (its unique identifier more precisely) which must contain the following sub-folders :
3rdparty
: Folder containing the external libraries used in the plugin (example for the SMS plugin a library for serial communication in php).core
: Folder containing all internal operating files.
class
: Folder containing the plugin class.php
: Folder that can contain functions that do not have to belong to a class (often used to allow the inclusion of multiple classes or configuration files at once).config
: Plugin configuration file.ajax
: Folder containing AJA call target filesX.i18n
: Folder containing files .plugin translation json.template
: Folder containing the html templates for tiles specific to the plugin’s equipment, in the dashboard and mobile subfolders.desktop
: Folder containing the “desktop” view of the plugin (in contrast to the “mobile” view”).
js
: Folder containing all javascript type files for the plugin interface.php
: Folder containing all php type files for the plugin interface.css
: If necessary, all the css files of the plugin, possibly including fonts.modal
: Folder containing the modal code of the plugin.img
: Folder for the images (png, jpg etc) needed by the plugin.plugin_info
: Contains the files allowing Jeedom to qualify the plugin, to install and configure it.
info.json
: File containing basic plugin information .It is mandatory otherwise Jeedom will not see the plugin. It contains, among other things, the module identifier, description, installation instructions, etcinstall.php
: File containing (if necessary) the methods for installing and uninstalling the plugin.configuration.php
: File containing the parameters to configure the plugin independent of its equipment (example for the Zwave module, the Raspberry Pi ip with the Razberry card)docs
: Must contain the plugin doc in markdown format, the root and the index.md file. All images are in docs / images. The doc itself is in a folder depending on the language (ex in French : docs/fr\_FR
)ressources
: Folder for possible daemons and dependencies.data
: Folder used for files generated by the plugin specific to the user’s Jeedom.As for the file naming convention, here are the requirements :
.class.php
nom\_class.class.php
.inc.php
.config.php
Here are the recommendations :
.ajax.php
info.json
View here
install.php
File giving instructions for installing a plugin :
It is composed as follows :
The first commented part contains the license (it’s better). The one used here indicates that the file belongs to Jeedom and that it is open source Then comes the inclusion of Jeedom’s core (this allows access to internal functions) Then come the 3 functions :
pluginid_install()
: method to install the plugin. Here the installation adds a cron job to Jeedompluginid_update()
: method to install the plugin. Used here to restart the cron taskpluginid_remove()
: method to remove the plugin. Here the function removes the cron task from Jeedom during the uninstallExample :
<?php
/ * This file is part of Jeedom.
*
* Jeedom is free software: you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jeedom is distributed in the hope that it will be useful,
* goal WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/
require_once dirname (__ FILE__). '/../../../core/php/core.inc.php';
function openzwave_install() {
$cron = cron::byClassAndFunction('zwave', 'pull');
yew (!is_object ($ cron)) {
$cron = new cron();
$cron->setClass('zwave');
$cron->setFunction('pull');
$cron->setEnable(1);
$cron->setDeamon(1);
$cron->setSchedule('* * * * *');
$cron->save();
}
}
function openzwave_update() {
$cron = cron::byClassAndFunction('zwave', 'pull');
yew (!is_object ($ cron)) {
$cron = new cron();
$cron->setClass('zwave');
$cron->setFunction('pull');
$cron->setEnable(1);
$cron->setDeamon(1);
$cron->setSchedule('* * * * *');
$cron->save();
}
$cron->stop();
}
function openzwave_remove() {
$cron = cron::byClassAndFunction('zwave', 'pull');
if (is_object ($ cron)) {
$cron->remove();
}
}
?>
configuration.php
Fichier permettant de demander des informations de configuration à l’utilisateur :
Le fichier est constitué de :
Ensuite vient le paramètre demandé (il peut en avoir plusieurs), c’est une syntaxe standard Bootstrap pour les formulaires, les seules particularités à respecter sont la classe (configKey
) à mettre sur l’élément de paramètre ainsi que le “data-l1key” qui indique le nom du paramètre. Pour récupérer la valeur de celui-ci ailleurs dans le plugin il suffit de faire : config::byKey(NOM_PARAMETRE, PLUGIN_ID)
Example :
<?php
/ * This file is part of Jeedom.
*
* Jeedom is free software: you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jeedom is distributed in the hope that it will be useful,
* goal WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/
require_once dirname (__ FILE__). '/../../../core/php/core.inc.php';
include_file ('core', 'authentication', 'php');
yew (!isConnect()) {
include_file('desktop', '404', 'php');
die();
}
?>
<form class="form-horizontal">
<fieldset>
<div class="form-group">
<label class="col-lg-2 control-label">Zway IP</label>
<div class="col-lg-2">
<input class="configKey form-control" data-l1key="zwaveAddr" />
</div>
</div>
<div class="form-group">
<label class="col-lg-4 control-label">Supprimer automatiquement les périphériques exclus</label>
<div class="col-lg-4">
<input type="checkbox" class="configKey" data-l1key="autoRemoveExcludeDevice" />
</div>
</div>
<div class="form-group">
<label class="col-lg-4 control-label">J'utilise un serveur openzwave</label>
<div class="col-lg-4">
<input type="checkbox" class="configKey" data-l1key="isOpenZwave" />
</div>
</div>
</fieldset>
</form>
This folder contains the view itself. Inside, you must find the plugin configuration page (the one that will appear when the user does the plugin ⇒ category ⇒ your plugin). It is advisable to name it with the id of your plugin. It can also contain the panel (page that the user will find in home → name of your plugin).
All files in this folder must end up .php
and must start with :
<?php
yew (!isConnect ('admin')) {
throw new Exception ('401');
}
sendVarToJS ('eqType', 'mail');
?>
Une fois sur cette page vous aurez accès en php à toutes les fonctions du core de jeedom (voir here ) ainsi qu’à celles de tous les modules installés donc le vôtre aussi.
Toutes ces pages étant des vues elles utilisent principalement la syntaxe HTML. Pour tout ce qui est présentation, Jeedom se base principalement sur bootstrap donc toute la documentation est applicable.
Pour simplifier la création de plugin vous pouvez inclure dans votre page le script javascript de template pour les plugins :
<?php include_file('core', 'plugin.template', 'js'); ?>
To put at the bottom of your page and useful only on the configuration page of your plugin. This script makes it possible to reduce the compulsory javascript to a single function (see section on JS files).
In your configuration page an HTML syntax has been implemented to simplify your life. So for most plugins you will only have to do HTML to store your information in the database and therefore use it on the side of your class.
The syntax is quite simple: your element (input, select…) must have the class css eqLogicAttr (or cmdAttr for commands) and an attribute indicating the name of the property :
<input type="text" class="eqLogicAttr form-control" data-l1key="name" placeholder=""/>
Là, par exemple, lors du chargement des données jeedom mettra la valeur du nom de l’équipement dans l’input et lors de la sauvegarde récupérera celle-ci pour la remettre en base de données. Petite astuce certaines propriétés sont en fait des chaînes JSON en BDD (cela permet d’avoir vraiment pas mal de liberté pour le plugin), dans ce cas il suffit de faire :
<input class="eqLogicAttr form-control" data-l1key='configuration' data-l2key='fromName' />
For the list of properties of equipment and commands it is here (to see the properties that are JSON just look at the getter or the setter, if it takes 2 parameters then it is JSON)
Last important point on the configuration page: this can contain as many equipment and commands as necessary. However there are a few rules to follow :
All elements having the class eqLogicAttr must be in an element having the class css eqLogic Ditto for elements of class css cmdAttr which must be in an element of class cmd. All the commands of an equipment must be in the element having the corresponding eqLogic class
All JS files must be in the JS folder (easy !!!). It is advisable to name it with the same ID as your plugin (in the configuration part, for the panel you do as you want). This JS file (that of the plugin configuration) must at least contain an addCmdToTable method which takes the command object to add as a parameter. Here is a simple example :
function addCmdToTable (_cmd) {
yew (!isset (_cmd)) {
var _cmd = {configuration: {}};
}
var tr = ''; tr + = '';
<html>tr + = ' : none; "> ';
tr + = '<input class="cmdAttr form-control input-sm" data-l1key="name"> '; tr + = '<input class="cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="recipient"> '; tr + = '';
<html>tr + = ' : none; "> ';
<html>tr + = ' : none; "> ';
if (is_numeric (_cmd.id)) {
tr + = ' <a class="btn btn-default btn-xs cmdAction" data-action="test"><i class="fa fa-rss"></i></a> ';
}
tr + = '<i class="fa fa-minus-circle pull-right cmdAction cursor" data-action="remove"></i></td> ';
tr + = '';
$('#table_cmd tbody').append(tr);
$('#table_cmd tbody tr:last').setValues(_cmd, '.cmdAttr');
}
Vous remarquerez qu’il y a une ligne par commande et que celle-ci a bien la classe css cmd. Vous pouvez aussi voir les éléments qui ont la classe cmdAttr.
Plusieurs points importants :
Dernier point: un exemple plus complet avec type et sous-type de commande :
function addCmdToTable (_cmd) {
yew (!isset (_cmd)) {
var _cmd = {};
}
yew (!isset (_cmd.configuration)) {
_cmd.configuration = {};
}
var selRequestType = '<select style="width : 90px;" class="cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="requestType">';
selRequestType += '<option value="script"></option>';
selRequestType += '<option value="http"></option>';
selRequestType += '</select>';
var tr = ''; tr += '<input class="cmdAttr form-control input-sm" data-l1key="name" style="width : 140px;">';
tr += '<input class="cmdAttr form-control input-sm" data-l1key="id" style="display : none; "> ';
tr += '' + selRequestType;
tr += '<div class="requestTypeConfig" data-type="http">';
tr += '<input type="checkbox" class="cmdAttr" data-l1key="configuration" data-l2key="noSslCheck" />Ne pas vérifier SSL';
tr += '</div>';
tr + = ''; tr + = '';
tr += '<span class="type" type="' + init(_cmd.type) + '">' + jeedom.cmd.availableType() + '</span>';
tr += '<span class="subType" subType="' + init(_cmd.subType) + '"></span>';
tr + = ''; tr += '<textarea style="height : 95px;" class="cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="request"></textarea>';
tr += '<a class="btn btn-default browseScriptFile cursor input-sm" style="margin-top : 5px;"><i class="fa fa-folder-open"></i> </a> ';
tr += '<a class="btn btn-default editScriptFile cursor input-sm" style="margin-top : 5px;"><i class="fa fa-edit"></i> </a> ';
tr += '<a class="btn btn-success newScriptFile cursor input-sm" style="margin-top : 5px;"><i class="fa fa-file-o"></i> </a> ';
tr += '<a class="btn btn-danger removeScriptFile cursor input-sm" style="margin-top : 5px;"><i class="fa fa-trash-o"></i> </a> ';
tr += '<a class="btn btn-warning bt_shareOnMarket cursor input-sm" style="margin-top : 5px;"><i class="fa fa-cloud-upload"></i> </a> ';
tr += '</div>';
tr + = ''; tr + = '';
tr += '<input class="cmdAttr form-control tooltips input-sm" data-l1key="unite" style="width : 100px;" placeholder="" title="">';
tr += '<input class="tooltips cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="minValue" placeholder="" title=""> ';
tr += '<input class="tooltips cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="maxValue" placeholder="" title="">';
tr + = ''; tr + = '';
tr += '<span><input type="checkbox" class="cmdAttr" data-l1key="isHistorized" /> <br/></span>';
tr + = ''; tr + = '';
if (is_numeric (_cmd.id)) {
tr + = ' <a class="btn btn-default btn-xs cmdAction" data-action="test"><i class="fa fa-rss"></i></a> ';
}
tr + = '<i class="fa fa-minus-circle pull-right cmdAction cursor" data-action="remove"></i></td> ';
tr + = '';
$('#table_cmd tbody').append(tr);
$('#table_cmd tbody tr:last').setValues(_cmd, '.cmdAttr');
yew (isset (_cmd.configuration.requestType)) {
$('#table_cmd tbody tr:last .cmdAttr[data-l1key=configuration][data-l2key=requestType]').value(init(_cmd.configuration.requestType));
$('#table_cmd tbody tr:last .cmdAttr[data-l1key=configuration][data-l2key=requestType]').trigger('change');
}
yew (isset (_cmd.type)) {
$('#table_cmd tbody tr:last .cmdAttr[data-l1key=type]').value(init(_cmd.type));
}
jeedom.cmd.changeType($('#table_cmd tbody tr:last'), init(_cmd.subType));
initTooltips();
}
Here we can notice :
jeedom.cmd.availableType()
will insert a select with the list of known types (action and info for the moment)<span class="subType" subType="' + init(\_cmd.subType) + '"><\span>
: the place where the select of sub type must be posedjeedom.cmd.changeType(\$('\#table\_cmd tbody tr:last'), init(\_cmd.subType))
which allows to initialize the subtype with the right valueOther javascript functions can be used :
printEqLogic
which takes the entire object of the equipment as a parameter (useful in the event of data processing before restoring it). It is called when the equipment data is displayedsaveEqLogic
which takes as a parameter the equipment object which will be saved in the database (useful if you need to do some processing before saving) Last thing, for JS files, here is how to include them in a clean way on your php page :<?php include_file('desktop', 'weather', 'js', 'weather'); ?>
Le premier argument donne le dossier dans lequel le trouver (attention c’est le dossier père du dossier JS), le deuxième le nom de votre javascript, le troisième indique à Jeedom que c’est un fichier Js et le dernier dans quel plugin il se trouve.
Ce dossier contient vos fichiers CSS (il ne devrait pas être trop utilisé) , vohere comment les inclure sur votre page :
<?php include_file('desktop', 'weather', 'css', 'weather'); ?>
The first argument gives the folder in which to find it (attention is the parent folder of the CSS folder), the second the name of your css file, the third tells Jeedom that it is a CSS file and the last in which plugin it turns out that.
The modal folder allows you to store your php files intended to display modals. Here’s how to call them from your main page (this code is in a javascript file) :
You can see :
$('#md_modal').dialog({title: ""}).load('index.php?v=d&plugin=zwave&modal=show.class&id=' + $('.eqLogicAttr[data-l1key=id]').value()).dialog('open')
La première ligne permet de mettre un titre à votre modal
La deuxième ligne charge votre modal et l’affichage. The syntax is quite simple : plugin, l’ID de votre plugin, modal, le nom de votre modal sans le php et ensuite les paramètres que vous voulez lui passer
Ce n’est pas un dossier mais dans les dernières versions de Jeedom celui-ci offre au développeur toute une api javascript (cela évite d’écrire des appels ajax dans tous les sens). J’essayerai de faire un article pour expliquer les différentes fonctionnalités mais vous pouvez déjà trouver le code here.
Voilà pour les détails du desktop folder. Je me doute qu’il n’est pas des plus complets (j’essayerai de le compléter en fonction des différentes demandes reçues) mais j’espère que grâce à lui vous pourrez commencer à faire des plugins pour Jeedom.
$('body').delegate('.helpSelectCron','click',function() {
var el = $(this).closest('.schedule').find('.scenarioAttr[data-l1key=schedule]')
jeedom.getCronSelectModal({},function (result) {
el.value(result.value)
})
})
When we click on the assistant button, we get the input to write in then we call the assistant. Once the configuration is finished in the wizard, the result is retrieved then written in the previously selected input
By far the most important folder of your plugin, it can include 4 subfolders.
NOTE : all along this part the id of your plugin will be referenced by : plugin_id
Contains the annex PHP files, I used to put for example an inclusion file if, of course, you have several class files or 3rparty to include
Which can contain 2 subfolders, dashboard and mobile, it is a folder that Jeedom automatically scans for a widget, so if you use specific widgets this is where you have to put their HTML file
This is where your translation should be in the form of a json file (best and look for example the plugin Zwave to see the shape of the file)
This folder is for all your ajax files, here is a skeleton of ajax file :
<?php
/ * This file is part of Jeedom.
*
* Jeedom is free software: you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jeedom is distributed in the hope that it will be useful,
* goal WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/
try {
require_once dirname (__ FILE__). '/../../../../core/php/core.inc.php';
include_file ('core', 'authentication', 'php');
yew (!isConnect ('admin')) {
throw new Exception (__ ('401 - Access not allowed', __FILE__));
}
if (init ('action') == 'your action') {
ajax::success ($ result);
}
throw new Exception (__ ('No method matching : ', __FILE__). init ('action'));
/* * *********Catch exception*************** */
} catch (Exception $ e) {
ajax::error (displayExeption ($ e), $ e-> getCode ());
}
?>
Dossier très important, c’est le moteur de votre plugin. C’est là que viennent les 2 classes obligatoires de votre plugin :
plugin\_id
plugin\_idCmd
La première devant hériter de la classe eqLogic et la deuxième de cmd. Vohere un template :
<?php
/ * This file is part of Jeedom.
*
* Jeedom is free software: you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jeedom is distributed in the hope that it will be useful,
* goal WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
*/
/* * ***************************Includes********************************* */
require_once dirname (__ FILE__). '/../../../../core/php/core.inc.php';
class plugin_ID extends eqLogic {
/* * *************************Attributs****************************** */
/* * ***********************Methode static*************************** */
/* * *********************Methode d'instance************************* */
/* * **********************Getteur Setteur*************************** */
}
class plugin_idCmd extends cmd {
/* * *************************Attributs****************************** */
/* * ***********************Methode static*************************** */
/* * *********************Methode d'instance************************* */
/* * **********************Getteur Setteur*************************** */
}
?>
For the definition of jeedom classes, I invite you to consult this SIte
The only mandatory method is the instance method on the cmd execute class, here is an example with the SARAH plugin :
public function execute ($ _ options = array()) {
yew (!isset ($ _ options ['title']) && !isset ($ _ options ['message'])) {
throw new Exception (__ ("Title or message cannot both be empty", __FILE__));
}
$eqLogic = $this->getEqLogic();
$message = '';
if (isset ($ _ options ['title'])) {
$message = $_options['title'] . '. ';
}
$message .= $_options['message'];
$http = new com_http($eqLogic->getConfiguration('addrSrvTts') . '/?tts=' . urlencode($message));
return $ http-> exec ();
}
Example assez simple mais complet, le principe est le suivant, si la commande est une action ou une info (mais pas en événement seulement et que son Cache est dépassé) alors jeedom appelle cette méthode.
Dans notre exemple here c’est une commande pour faire parler S.A.R.A.H, où le plugin récupère les paramètres dans $_options (attention c’est un tableau et ses attributs changent en fonction du sous-type de la commande : color pour un sous-type color, slider pour un sous-type slider, title et message pour un sous-type message et vide pour un sous-type other).
Voila pour la partie obligatoire, voila maintenant ce qui peut être utilisé à coté (avec exemple) :
Fonction utilisable dans la commande ou dans l’équipement, en fonction des besoins, vohere un exemple pour l’équipement
public function toHtml($_version = 'dashboard') {
$replace = $this->preToHtml($_version);
yew (!is_array($replace)) {
return $replace;
}
$version = jeedom::versionAlias($_version);
$replace['#forecast#'] = '';
yew ($version != 'mobile' || $this->getConfiguration('fullMobileDisplay', 0) == 1) {
$forcast_template = getTemplate('core', $version, 'forecast', 'weather');
for ($i = 0; $i < 5; $i++) {
$replaceDay = array();
$replaceDay['#day#'] = date_fr(date('l', strtotime('+' . $i . ' days')));
yew ($i == 0) {
$temperature_min = $this->getCmd(null, 'temperature_min');
} else {
$temperature_min = $this->getCmd(null, 'temperature_' . $i . '_min');
}
$replaceDay['#low_temperature#'] = is_object($temperature_min) ? $temperature_min->execCmd() : '';
yew ($i == 0) {
$temperature_max = $this->getCmd(null, 'temperature_max');
} else {
$temperature_max = $this->getCmd(null, 'temperature_' . $i . '_max');
}
$replaceDay['#hight_temperature#'] = is_object($temperature_max) ? $temperature_max->execCmd() : '';
$replaceDay['#tempid#'] = is_object($temperature_max) ? $temperature_max->getId() : '';
yew ($i == 0) {
$condition = $this->getCmd(null, 'condition');
} else {
$condition = $this->getCmd(null, 'condition_' . $i);
}
$replaceDay['#icone#'] = is_object($condition) ? self::getIconFromCondition($condition->execCmd()) : '';
$replaceDay['#conditionid#'] = is_object($condition) ? $condition->getId() : '';
$replace['#forecast#'] .= template_replace($replaceDay, $forcast_template);
}
}
$temperature = $this->getCmd(null, 'temperature');
$replace['#temperature#'] = is_object($temperature) ? $temperature->execCmd() : '';
$replace['#tempid#'] = is_object($temperature) ? $temperature->getId() : '';
$humidity = $this->getCmd(null, 'humidity');
$replace['#humidity#'] = is_object($humidity) ? $humidity->execCmd() : '';
$pressure = $this->getCmd(null, 'pressure');
$replace['#pressure#'] = is_object($pressure) ? $pressure->execCmd() : '';
$replace['#pressureid#'] = is_object($pressure) ? $pressure->getId() : '';
$wind_speed = $this->getCmd(null, 'wind_speed');
$replace['#windspeed#'] = is_object($wind_speed) ? $wind_speed->execCmd() : '';
$replace['#windid#'] = is_object($wind_speed) ? $wind_speed->getId() : '';
$sunrise = $this->getCmd(null, 'sunrise');
$replace['#sunrise#'] = is_object($sunrise) ? $sunrise->execCmd() : '';
$replace['#sunid#'] = is_object($sunrise) ? $sunrise->getId() : '';
yew (strlen($replace['#sunrise#']) == 3) {
$replace['#sunrise#'] = substr($replace['#sunrise#'], 0, 1) . ':' . substr($replace['#sunrise#'], 1, 2);
} else yew (strlen($replace['#sunrise#']) == 4) {
$replace['#sunrise#'] = substr($replace['#sunrise#'], 0, 2) . ':' . substr($replace['#sunrise#'], 2, 2);
}
$sunset = $this->getCmd(null, 'sunset');
$replace['#sunset#'] = is_object($sunset) ? $sunset->execCmd() : '';
yew (strlen($replace['#sunset#']) == 3) {
$replace['#sunset#'] = substr($replace['#sunset#'], 0, 1) . ':' . substr($replace['#sunset#'], 1, 2);
} else yew (strlen($replace['#sunset#']) == 4) {
$replace['#sunset#'] = substr($replace['#sunset#'], 0, 2) . ':' . substr($replace['#sunset#'], 2, 2);
}
$wind_direction = $this->getCmd(null, 'wind_direction');
$replace['#wind_direction#'] = is_object($wind_direction) ? $wind_direction->execCmd() : 0;
$refresh = $this->getCmd(null, 'refresh');
$replace['#refresh_id#'] = is_object($refresh) ? $refresh->getId() : '';
$condition = $this->getCmd(null, 'condition_now');
$sunset_time = is_object($sunset) ? $sunset->execCmd() : null;
$sunrise_time = is_object($sunrise) ? $sunrise->execCmd() : null;
yew (is_object($condition)) {
$replace['#icone#'] = self::getIconFromCondition($condition->execCmd(), $sunrise_time, $sunset_time);
$replace['#condition#'] = $condition->execCmd();
$replace['#conditionid#'] = $condition->getId();
$replace['#collectDate#'] = $condition->getCollectDate();
} else {
$replace['#icone#'] = '';
$replace['#condition#'] = '';
$replace['#collectDate#'] = '';
}
yew ($this->getConfiguration('modeImage', 0) == 1) {
$replace['#visibilityIcon#'] = "none";
$replace['#visibilityImage#'] = "block";
} else {
$replace['#visibilityIcon#'] = "block";
$replace['#visibilityImage#'] = "none";
}
$l'opération à mener = template_replace($replace, getTemplate('core', $version, 'current', 'weather'));
cache::set('widgetHtml' . $_version . $this->getId(), $html, 0);
return $html;
}
Several interesting things here :
To convert the requested version into dashboard or mobile (mview becomes mobile for example, this allows for example on the views to add the name of the objects)
$_version = jeedom::versionAlias($_version);
Récupération d’un template de commande, here le template de commande : plugins/weather/core/template/$_version/forecast.l’opération à mener ($_version valant mobile ou dashboard)
$forcast_template = getTemplate('core', $_version, 'forecast', 'weather');
Here replace the previously filled tags in \ $ replace HTML to contain the values
$html_forecast .= template_replace($replace, $forcast_template);
Cela permet de récupérer la commande ayant le logical_ID : temperature_min
$this->getCmd(null, 'temperature_min');
Here it allows to put the value in the tag, only if the order has been retrieved
$replace['#temperature#'] = is_object($temperature) ? $temperature->execCmd() : '';
Passage important: cela permet de récupérer les personnalisations faites par l’utilisateur sur la page Générale → Affichage et de les réinjecter dans le template
$parameters = $this->getDisplay('parameters');
yew (is_array($parameters)) {
foreach ($parameters as $key => $value) {
$replace['#' . $key . '#'] = $value;
}
}
Saving the widget in the cache: so that during the next request we provide it faster, we can notice the 0 here which indicates an infinite lifespan, otherwise the duration is in seconds (we will see in the next part how the weather plugin updates its widget).
cache::set ('weatherWidget' . $_version . $this->getId(), $html, 0);
Enfin envoi du l’opération à mener à Jeedom :
return $html;
You must also tell Jeedom what your widget allows in terms of customization. It’s a bit complex (and again) but normally flexible and simple to set up.
It works the same way on your equipment or control, it is a static attribute of the class \ $_ widgetPossibility which must be a multidimensional array, but it is there that it becomes complicated if a dimension of the array is true or false. It then considers that all possible children are at this value (I will give an example).
First the cases where you must use it: if in your class inheriting from eqLogic or cmd has a toHtml function otherwise it is not worth reading more.
When creating or deleting your objects (equipment, order or other) in Jeedom, it can call several methods before / after the action :
preInsert
⇒ Method called before the creation of your objectpostInsert
⇒ Method called after the creation of your objectpreUpdate
⇒ Method called before updating your objectpostUpdate
⇒ Method called after updating your objectpreSave
⇒ Method called before saving (creation and update therefore) of your objectpostSave
⇒ Method called after saving your objectpreRemove
⇒ Method called before deleting your objectpostRemove
⇒ Method called after deleting your objectExample, always with the weather plugin for creating orders or updating them after saving (the example is simplified) :
public function postUpdate() {
$weatherCmd = $this->getCmd(null, 'temperature');
yew (!is_object ($ weatherCmd)) {
$weatherCmd = new weatherCmd();
}
$weatherCmd->setName(__('Température', __FILE__));
$weatherCmd->setLogicalId('temperature');
$weatherCmd->setEqLogic_id($this->getId());
$weatherCmd->setConfiguration('day', '-1');
$weatherCmd->setConfiguration('data', 'temp');
$weatherCmd->setUnite('°C');
$weatherCmd->setType('info');
$weatherCmd->setSubType('numeric');
$weatherCmd->save();
$cron = cron::byClassAndFunction('weather', 'updateWeatherData', array('weather_id' => intval($this->getId())));
yew (!is_object ($ cron)) {
$cron = new cron();
$cron->setClass('weather');
$cron->setFunction('updateWeatherData');
$cron->setOption(array('weather_id' => intval($this->getId())));
}
$cron->setSchedule($this->getConfiguration('refreshCron', '*/30 * * * *'));
$cron->save();
}
Le début est assez standard avec la création d’une commande, la fin est plus intéressante avec la mise en place d’un cron qui va appeler la méthode weather::updateWeatherData
en passant l’ID de l’équipement à mettre à jour toute les 30min par défaut.
Ici la méthode updateWeatherData (simplifiée aussi) :
public static function updateWeatherData($_options) {
$weather = weather::byId($_options['weather_id']);
yew (is_object($weather)) {
foreach ($weather->getCmd('info') as $cmd) {
$weather->checkAndUpdateCmd($cmd,$cmd->execute());
}
}
}
We see here that during the call we recover the equipment concerned then we execute the commands to recover the values and update them if necessary.
Very important part :
$weather->checkAndUpdateCmd($cmd,$cmd->execute());
Au moment de la fonction checkAndUpdateCmd
(qui permet de signaler à Jeedom une nouvelle mise à jour de la valeur, avec déclenchement de toutes les actions qui doivent être faites : mise à jour du dashboard, vérification des scénarios…),
Pour la classe commande, un petit truc à savoir si vous utilisez le template js de base. Lors de l’envoi de l’équipement Jeedom fait du différentiel sur les commandes et va supprimer celles qui sont en base mais pas dans la nouvelle définition de l’équipement. Voilà comment l’éviter :
public function dontRemoveCmd() {
return true;
}
To finish here are some tips and tricks :
$eqLogic->batteryStatus(56);
formatValue($_value)
qui, en fonction du sous-type, peut la remettre en forme (en particulier pour les valeurs binaires)