Browse code

init witj jeedom template

louis.jonget authored on17/01/2023 08:47:47
Showing28 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+nbproject/
2
+test.php
3
+core/config/common.config.php
4
+plugins
5
+sftp-config.json
6
+.project
7
+.DS_Store
8
+Thumbs.db
9
+*.php~
10
+docs/_site/
11
+docs/Gemfile.lock
12
+docs/.sass-cache/
13
+.remote-sync.json
14
+.vscode
0 15
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+Ce dossier doit contenir toutes les librairies externes utilisées par votre plugin.
0 2
new file mode 100644
... ...
@@ -0,0 +1,340 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Lesser General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    {description}
294
+    Copyright (C) {year}  {fullname}
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License along
307
+    with this program; if not, write to the Free Software Foundation, Inc.,
308
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+Also add information on how to contact you by electronic and paper mail.
311
+
312
+If the program is interactive, make it output a short notice like this
313
+when it starts in an interactive mode:
314
+
315
+    Gnomovision version 69, Copyright (C) year name of author
316
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+    This is free software, and you are welcome to redistribute it
318
+    under certain conditions; type `show c' for details.
319
+
320
+The hypothetical commands `show w' and `show c' should show the appropriate
321
+parts of the General Public License.  Of course, the commands you use may
322
+be called something other than `show w' and `show c'; they could even be
323
+mouse-clicks or menu items--whatever suits your program.
324
+
325
+You should also get your employer (if you work as a programmer) or your
326
+school, if any, to sign a "copyright disclaimer" for the program, if
327
+necessary.  Here is a sample; alter the names:
328
+
329
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+  {signature of Ty Coon}, 1 April 1989
333
+  Ty Coon, President of Vice
334
+
335
+This General Public License does not permit incorporating your program into
336
+proprietary programs.  If your program is a subroutine library, you may
337
+consider it more useful to permit linking proprietary applications with the
338
+library.  If this is what you want to do, use the GNU Lesser General
339
+Public License instead of this License.
340
+
0 341
new file mode 100644
... ...
@@ -0,0 +1,11 @@
1
+# Template de plugin pour Jeedom
2
+
3
+Ce "template de plugin" sert de base à la réalisation de plugins pour **Jeedom**.
4
+
5
+La documentation générale relative à la conception de plugin est consultable [ici](https://doc.jeedom.com/fr_FR/dev/). Dans le détail :   
6
+* [Utilisation du template de plugin](https://doc.jeedom.com/fr_FR/dev/plugin_template) : Le template de plugin est une base de plugin pour Jeedom qui doit être adaptée avec l'id de votre plugin et à laquelle il suffit d'ajouter vos propres fonctions. 
7
+* [Fichier info.json](https://doc.jeedom.com/fr_FR/dev/structure_info_json) : Intégré depuis la version 3.0 de Jeedom, le fichier **info.json** est obligatoire pour le bon fonctionnement des plugins et leur bon déploiement sur le Market Jeedom.
8
+* [Icône du plugin](https://doc.jeedom.com/fr_FR/dev/Icone_de_plugin) : Afin de pouvoir être publié sur le Market Jeedom, tout plugin doit disposer d’une icône. Attention à ne pas utiliser le même code couleur que les icônes des plugins Jeedom officiels.
9
+* [Widget du plugin](https://doc.jeedom.com/fr_FR/dev/widget_plugin) : Présentation des différentes manières d'inclure des widgets personnalisés au plugin.
10
+* [Documentation du plugin](https://doc.jeedom.com/fr_FR/dev/documentation_plugin) : Présentation de la mise en place d'une documentation car un bon plugin n'est rien sans documentation adéquate.
11
+* [Publication du plugin](https://doc.jeedom.com/fr_FR/dev/publication_plugin) : Description des pré-requis indispensables à la publication du plugin.
0 12
new file mode 100644
... ...
@@ -0,0 +1,39 @@
1
+<?php
2
+/* This file is part of Jeedom.
3
+ *
4
+ * Jeedom is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation, either version 3 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * Jeedom is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+try {
19
+    require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php';
20
+    include_file('core', 'authentification', 'php');
21
+
22
+    if (!isConnect('admin')) {
23
+        throw new Exception(__('401 - Accès non autorisé', __FILE__));
24
+    }
25
+
26
+  /* Fonction permettant l'envoi de l'entête 'Content-Type: application/json'
27
+    En V3 : indiquer l'argument 'true' pour contrôler le token d'accès Jeedom
28
+    En V4 : autoriser l'exécution d'une méthode 'action' en GET en indiquant le(s) nom(s) de(s) action(s) dans un tableau en argument
29
+  */
30
+    ajax::init();
31
+
32
+
33
+
34
+    throw new Exception(__('Aucune méthode correspondante à', __FILE__) . ' : ' . init('action'));
35
+    /*     * *********Catch exeption*************** */
36
+}
37
+catch (Exception $e) {
38
+    ajax::error(displayException($e), $e->getCode());
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+Order allow,deny
2
+Deny from all
0 3
new file mode 100644
... ...
@@ -0,0 +1,169 @@
1
+<?php
2
+/* This file is part of Jeedom.
3
+*
4
+* Jeedom is free software: you can redistribute it and/or modify
5
+* it under the terms of the GNU General Public License as published by
6
+* the Free Software Foundation, either version 3 of the License, or
7
+* (at your option) any later version.
8
+*
9
+* Jeedom is distributed in the hope that it will be useful,
10
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+* GNU General Public License for more details.
13
+*
14
+* You should have received a copy of the GNU General Public License
15
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
16
+*/
17
+
18
+/* * ***************************Includes********************************* */
19
+require_once __DIR__  . '/../../../../core/php/core.inc.php';
20
+
21
+class template extends eqLogic {
22
+  /*     * *************************Attributs****************************** */
23
+
24
+  /*
25
+  * Permet de définir les possibilités de personnalisation du widget (en cas d'utilisation de la fonction 'toHtml' par exemple)
26
+  * Tableau multidimensionnel - exemple: array('custom' => true, 'custom::layout' => false)
27
+  public static $_widgetPossibility = array();
28
+  */
29
+
30
+  /*
31
+  * Permet de crypter/décrypter automatiquement des champs de configuration du plugin
32
+  * Exemple : "param1" & "param2" seront cryptés mais pas "param3"
33
+  public static $_encryptConfigKey = array('param1', 'param2');
34
+  */
35
+
36
+  /*     * ***********************Methode static*************************** */
37
+
38
+  /*
39
+  * Fonction exécutée automatiquement toutes les minutes par Jeedom
40
+  public static function cron() {}
41
+  */
42
+
43
+  /*
44
+  * Fonction exécutée automatiquement toutes les 5 minutes par Jeedom
45
+  public static function cron5() {}
46
+  */
47
+
48
+  /*
49
+  * Fonction exécutée automatiquement toutes les 10 minutes par Jeedom
50
+  public static function cron10() {}
51
+  */
52
+
53
+  /*
54
+  * Fonction exécutée automatiquement toutes les 15 minutes par Jeedom
55
+  public static function cron15() {}
56
+  */
57
+
58
+  /*
59
+  * Fonction exécutée automatiquement toutes les 30 minutes par Jeedom
60
+  public static function cron30() {}
61
+  */
62
+
63
+  /*
64
+  * Fonction exécutée automatiquement toutes les heures par Jeedom
65
+  public static function cronHourly() {}
66
+  */
67
+
68
+  /*
69
+  * Fonction exécutée automatiquement tous les jours par Jeedom
70
+  public static function cronDaily() {}
71
+  */
72
+
73
+  /*     * *********************Méthodes d'instance************************* */
74
+
75
+  // Fonction exécutée automatiquement avant la création de l'équipement
76
+  public function preInsert() {
77
+  }
78
+
79
+  // Fonction exécutée automatiquement après la création de l'équipement
80
+  public function postInsert() {
81
+  }
82
+
83
+  // Fonction exécutée automatiquement avant la mise à jour de l'équipement
84
+  public function preUpdate() {
85
+  }
86
+
87
+  // Fonction exécutée automatiquement après la mise à jour de l'équipement
88
+  public function postUpdate() {
89
+  }
90
+
91
+  // Fonction exécutée automatiquement avant la sauvegarde (création ou mise à jour) de l'équipement
92
+  public function preSave() {
93
+  }
94
+
95
+  // Fonction exécutée automatiquement après la sauvegarde (création ou mise à jour) de l'équipement
96
+  public function postSave() {
97
+  }
98
+
99
+  // Fonction exécutée automatiquement avant la suppression de l'équipement
100
+  public function preRemove() {
101
+  }
102
+
103
+  // Fonction exécutée automatiquement après la suppression de l'équipement
104
+  public function postRemove() {
105
+  }
106
+
107
+  /*
108
+  * Permet de crypter/décrypter automatiquement des champs de configuration des équipements
109
+  * Exemple avec le champ "Mot de passe" (password)
110
+  public function decrypt() {
111
+    $this->setConfiguration('password', utils::decrypt($this->getConfiguration('password')));
112
+  }
113
+  public function encrypt() {
114
+    $this->setConfiguration('password', utils::encrypt($this->getConfiguration('password')));
115
+  }
116
+  */
117
+
118
+  /*
119
+  * Permet de modifier l'affichage du widget (également utilisable par les commandes)
120
+  public function toHtml($_version = 'dashboard') {}
121
+  */
122
+
123
+  /*
124
+  * Permet de déclencher une action avant modification d'une variable de configuration du plugin
125
+  * Exemple avec la variable "param3"
126
+  public static function preConfig_param3( $value ) {
127
+    // do some checks or modify on $value
128
+    return $value;
129
+  }
130
+  */
131
+
132
+  /*
133
+  * Permet de déclencher une action après modification d'une variable de configuration du plugin
134
+  * Exemple avec la variable "param3"
135
+  public static function postConfig_param3($value) {
136
+    // no return value
137
+  }
138
+  */
139
+
140
+  /*     * **********************Getteur Setteur*************************** */
141
+
142
+}
143
+
144
+class templateCmd extends cmd {
145
+  /*     * *************************Attributs****************************** */
146
+
147
+  /*
148
+  public static $_widgetPossibility = array();
149
+  */
150
+
151
+  /*     * ***********************Methode static*************************** */
152
+
153
+
154
+  /*     * *********************Methode d'instance************************* */
155
+
156
+  /*
157
+  * Permet d'empêcher la suppression des commandes même si elles ne sont pas dans la nouvelle configuration de l'équipement envoyé en JS
158
+  public function dontRemoveCmd() {
159
+    return true;
160
+  }
161
+  */
162
+
163
+  // Exécution d'une commande
164
+  public function execute($_options = array()) {
165
+  }
166
+
167
+  /*     * **********************Getteur Setteur*************************** */
168
+
169
+}
0 170
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+Order allow,deny
2
+Deny from all
0 3
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+<?php
2
+/* This file is part of Jeedom.
3
+*
4
+* Jeedom is free software: you can redistribute it and/or modify
5
+* it under the terms of the GNU General Public License as published by
6
+* the Free Software Foundation, either version 3 of the License, or
7
+* (at your option) any later version.
8
+*
9
+* Jeedom is distributed in the hope that it will be useful,
10
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+* GNU General Public License for more details.
13
+*
14
+* You should have received a copy of the GNU General Public License
15
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
16
+*/
17
+
18
+require_once __DIR__  . '/../../../../core/php/core.inc.php';
19
+/*
20
+*
21
+* Fichier d’inclusion si vous avez plusieurs fichiers de class ou 3rdParty à inclure
22
+*
23
+*/
0 24
new file mode 100644
1 25
new file mode 100644
2 26
new file mode 100644
... ...
@@ -0,0 +1,87 @@
1
+/* This file is part of Jeedom.
2
+*
3
+* Jeedom is free software: you can redistribute it and/or modify
4
+* it under the terms of the GNU General Public License as published by
5
+* the Free Software Foundation, either version 3 of the License, or
6
+* (at your option) any later version.
7
+*
8
+* Jeedom is distributed in the hope that it will be useful,
9
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+* GNU General Public License for more details.
12
+*
13
+* You should have received a copy of the GNU General Public License
14
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
15
+*/
16
+
17
+/* Permet la réorganisation des commandes dans l'équipement */
18
+$("#table_cmd").sortable({
19
+  axis: "y",
20
+  cursor: "move",
21
+  items: ".cmd",
22
+  placeholder: "ui-state-highlight",
23
+  tolerance: "intersect",
24
+  forcePlaceholderSize: true
25
+})
26
+
27
+/* Fonction permettant l'affichage des commandes dans l'équipement */
28
+function addCmdToTable(_cmd) {
29
+  if (!isset(_cmd)) {
30
+    var _cmd = {configuration: {}}
31
+  }
32
+  if (!isset(_cmd.configuration)) {
33
+    _cmd.configuration = {}
34
+  }
35
+  var tr = '<tr class="cmd" data-cmd_id="' + init(_cmd.id) + '">'
36
+  tr += '<td class="hidden-xs">'
37
+  tr += '<span class="cmdAttr" data-l1key="id"></span>'
38
+  tr += '</td>'
39
+  tr += '<td>'
40
+  tr += '<div class="input-group">'
41
+  tr += '<input class="cmdAttr form-control input-sm roundedLeft" data-l1key="name" placeholder="{{Nom de la commande}}">'
42
+  tr += '<span class="input-group-btn"><a class="cmdAction btn btn-sm btn-default" data-l1key="chooseIcon" title="{{Choisir une icône}}"><i class="fas fa-icons"></i></a></span>'
43
+  tr += '<span class="cmdAttr input-group-addon roundedRight" data-l1key="display" data-l2key="icon" style="font-size:19px;padding:0 5px 0 0!important;"></span>'
44
+  tr += '</div>'
45
+  tr += '<select class="cmdAttr form-control input-sm" data-l1key="value" style="display:none;margin-top:5px;" title="{{Commande info liée}}">'
46
+  tr += '<option value="">{{Aucune}}</option>'
47
+  tr += '</select>'
48
+  tr += '</td>'
49
+  tr += '<td>'
50
+  tr += '<span class="type" type="' + init(_cmd.type) + '">' + jeedom.cmd.availableType() + '</span>'
51
+  tr += '<span class="subType" subType="' + init(_cmd.subType) + '"></span>'
52
+  tr += '</td>'
53
+  tr += '<td>'
54
+  tr += '<label class="checkbox-inline"><input type="checkbox" class="cmdAttr" data-l1key="isVisible" checked/>{{Afficher}}</label> '
55
+  tr += '<label class="checkbox-inline"><input type="checkbox" class="cmdAttr" data-l1key="isHistorized" checked/>{{Historiser}}</label> '
56
+  tr += '<label class="checkbox-inline"><input type="checkbox" class="cmdAttr" data-l1key="display" data-l2key="invertBinary"/>{{Inverser}}</label> '
57
+  tr += '<div style="margin-top:7px;">'
58
+  tr += '<input class="tooltips cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="minValue" placeholder="{{Min}}" title="{{Min}}" style="width:30%;max-width:80px;display:inline-block;margin-right:2px;">'
59
+  tr += '<input class="tooltips cmdAttr form-control input-sm" data-l1key="configuration" data-l2key="maxValue" placeholder="{{Max}}" title="{{Max}}" style="width:30%;max-width:80px;display:inline-block;margin-right:2px;">'
60
+  tr += '<input class="tooltips cmdAttr form-control input-sm" data-l1key="unite" placeholder="Unité" title="{{Unité}}" style="width:30%;max-width:80px;display:inline-block;margin-right:2px;">'
61
+  tr += '</div>'
62
+  tr += '</td>'
63
+  tr += '<td>';
64
+  tr += '<span class="cmdAttr" data-l1key="htmlstate"></span>'; 
65
+  tr += '</td>';
66
+  tr += '<td>'
67
+  if (is_numeric(_cmd.id)) {
68
+    tr += '<a class="btn btn-default btn-xs cmdAction" data-action="configure"><i class="fas fa-cogs"></i></a> '
69
+    tr += '<a class="btn btn-default btn-xs cmdAction" data-action="test"><i class="fas fa-rss"></i> Tester</a>'
70
+  }
71
+  tr += '<i class="fas fa-minus-circle pull-right cmdAction cursor" data-action="remove" title="{{Supprimer la commande}}"></i></td>'
72
+  tr += '</tr>'
73
+  $('#table_cmd tbody').append(tr)
74
+  var tr = $('#table_cmd tbody tr').last()
75
+  jeedom.eqLogic.buildSelectCmd({
76
+    id:  $('.eqLogicAttr[data-l1key=id]').value(),
77
+    filter: {type: 'info'},
78
+    error: function (error) {
79
+      $('#div_alert').showAlert({message: error.message, level: 'danger'})
80
+    },
81
+    success: function (result) {
82
+      tr.find('.cmdAttr[data-l1key=value]').append(result)
83
+      tr.setValues(_cmd, '.cmdAttr')
84
+      jeedom.cmd.changeType(tr, init(_cmd.subType))
85
+    }
86
+  })
87
+}
0 88
new file mode 100644
... ...
@@ -0,0 +1,25 @@
1
+<?php
2
+
3
+/* This file is part of Jeedom.
4
+*
5
+* Jeedom is free software: you can redistribute it and/or modify
6
+* it under the terms of the GNU General Public License as published by
7
+* the Free Software Foundation, either version 3 of the License, or
8
+* (at your option) any later version.
9
+*
10
+* Jeedom is distributed in the hope that it will be useful,
11
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+* GNU General Public License for more details.
14
+*
15
+* You should have received a copy of the GNU General Public License
16
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
17
+*/
18
+
19
+if (!isConnect('admin')) {
20
+    throw new Exception('{{401 - Accès non autorisé}}');
21
+}
22
+?>
23
+
24
+Exemple de modale
25
+
0 26
new file mode 100644
... ...
@@ -0,0 +1,209 @@
1
+<?php
2
+if (!isConnect('admin')) {
3
+	throw new Exception('{{401 - Accès non autorisé}}');
4
+}
5
+// Déclaration des variables obligatoires
6
+$plugin = plugin::byId('template');
7
+sendVarToJS('eqType', $plugin->getId());
8
+$eqLogics = eqLogic::byType($plugin->getId());
9
+?>
10
+
11
+<div class="row row-overflow">
12
+	<!-- Page d'accueil du plugin -->
13
+	<div class="col-xs-12 eqLogicThumbnailDisplay">
14
+		<legend><i class="fas fa-cog"></i>  {{Gestion}}</legend>
15
+		<!-- Boutons de gestion du plugin -->
16
+		<div class="eqLogicThumbnailContainer">
17
+			<div class="cursor eqLogicAction logoPrimary" data-action="add">
18
+				<i class="fas fa-plus-circle"></i>
19
+				<br>
20
+				<span>{{Ajouter}}</span>
21
+			</div>
22
+			<div class="cursor eqLogicAction logoSecondary" data-action="gotoPluginConf">
23
+				<i class="fas fa-wrench"></i>
24
+				<br>
25
+				<span>{{Configuration}}</span>
26
+			</div>
27
+		</div>
28
+		<legend><i class="fas fa-table"></i> {{Mes templates}}</legend>
29
+		<?php
30
+		if (count($eqLogics) == 0) {
31
+			echo '<br><div class="text-center" style="font-size:1.2em;font-weight:bold;">{{Aucun équipement Template trouvé, cliquer sur "Ajouter" pour commencer}}</div>';
32
+		} else {
33
+			// Champ de recherche
34
+			echo '<div class="input-group" style="margin:5px;">';
35
+			echo '<input class="form-control roundedLeft" placeholder="{{Rechercher}}" id="in_searchEqlogic">';
36
+			echo '<div class="input-group-btn">';
37
+			echo '<a id="bt_resetSearch" class="btn" style="width:30px"><i class="fas fa-times"></i></a>';
38
+			echo '<a class="btn roundedRight hidden" id="bt_pluginDisplayAsTable" data-coreSupport="1" data-state="0"><i class="fas fa-grip-lines"></i></a>';
39
+			echo '</div>';
40
+			echo '</div>';
41
+			// Liste des équipements du plugin
42
+			echo '<div class="eqLogicThumbnailContainer">';
43
+			foreach ($eqLogics as $eqLogic) {
44
+				$opacity = ($eqLogic->getIsEnable()) ? '' : 'disableCard';
45
+				echo '<div class="eqLogicDisplayCard cursor '.$opacity.'" data-eqLogic_id="' . $eqLogic->getId() . '">';
46
+				echo '<img src="' . $plugin->getPathImgIcon() . '">';
47
+				echo '<br>';
48
+				echo '<span class="name">' . $eqLogic->getHumanName(true, true) . '</span>';
49
+				echo '<span class="hiddenAsCard displayTableRight hidden">';
50
+				echo ($eqLogic->getIsVisible() == 1) ? '<i class="fas fa-eye" title="{{Equipement visible}}"></i>' : '<i class="fas fa-eye-slash" title="{{Equipement non visible}}"></i>';
51
+				echo '</span>';
52
+				echo '</div>';
53
+			}
54
+			echo '</div>';
55
+		}
56
+		?>
57
+	</div> <!-- /.eqLogicThumbnailDisplay -->
58
+
59
+	<!-- Page de présentation de l'équipement -->
60
+	<div class="col-xs-12 eqLogic" style="display: none;">
61
+		<!-- barre de gestion de l'équipement -->
62
+		<div class="input-group pull-right" style="display:inline-flex;">
63
+			<span class="input-group-btn">
64
+				<!-- Les balises <a></a> sont volontairement fermées à la ligne suivante pour éviter les espaces entre les boutons. Ne pas modifier -->
65
+				<a class="btn btn-sm btn-default eqLogicAction roundedLeft" data-action="configure"><i class="fas fa-cogs"></i><span class="hidden-xs"> {{Configuration avancée}}</span>
66
+				</a><a class="btn btn-sm btn-default eqLogicAction" data-action="copy"><i class="fas fa-copy"></i><span class="hidden-xs">  {{Dupliquer}}</span>
67
+				</a><a class="btn btn-sm btn-success eqLogicAction" data-action="save"><i class="fas fa-check-circle"></i> {{Sauvegarder}}
68
+				</a><a class="btn btn-sm btn-danger eqLogicAction roundedRight" data-action="remove"><i class="fas fa-minus-circle"></i> {{Supprimer}}
69
+				</a>
70
+			</span>
71
+		</div>
72
+		<!-- Onglets -->
73
+		<ul class="nav nav-tabs" role="tablist">
74
+			<li role="presentation"><a href="#" class="eqLogicAction" aria-controls="home" role="tab" data-toggle="tab" data-action="returnToThumbnailDisplay"><i class="fas fa-arrow-circle-left"></i></a></li>
75
+			<li role="presentation" class="active"><a href="#eqlogictab" aria-controls="home" role="tab" data-toggle="tab"><i class="fas fa-tachometer-alt"></i> {{Equipement}}</a></li>
76
+			<li role="presentation"><a href="#commandtab" aria-controls="home" role="tab" data-toggle="tab"><i class="fas fa-list"></i> {{Commandes}}</a></li>
77
+		</ul>
78
+		<div class="tab-content">
79
+			<!-- Onglet de configuration de l'équipement -->
80
+			<div role="tabpanel" class="tab-pane active" id="eqlogictab">
81
+				<!-- Partie gauche de l'onglet "Equipements" -->
82
+				<!-- Paramètres généraux et spécifiques de l'équipement -->
83
+				<form class="form-horizontal">
84
+					<fieldset>
85
+						<div class="col-lg-6">
86
+							<legend><i class="fas fa-wrench"></i> {{Paramètres généraux}}</legend>
87
+							<div class="form-group">
88
+								<label class="col-sm-4 control-label">{{Nom de l'équipement}}</label>
89
+								<div class="col-sm-6">
90
+									<input type="text" class="eqLogicAttr form-control" data-l1key="id" style="display:none;">
91
+									<input type="text" class="eqLogicAttr form-control" data-l1key="name" placeholder="{{Nom de l'équipement}}">
92
+								</div>
93
+							</div>
94
+							<div class="form-group">
95
+								<label class="col-sm-4 control-label" >{{Objet parent}}</label>
96
+								<div class="col-sm-6">
97
+									<select id="sel_object" class="eqLogicAttr form-control" data-l1key="object_id">
98
+										<option value="">{{Aucun}}</option>
99
+										<?php
100
+										$options = '';
101
+										foreach ((jeeObject::buildTree(null, false)) as $object) {
102
+											$options .= '<option value="' . $object->getId() . '">' . str_repeat('&nbsp;&nbsp;', $object->getConfiguration('parentNumber')) . $object->getName() . '</option>';
103
+										}
104
+										echo $options;
105
+										?>
106
+									</select>
107
+								</div>
108
+							</div>
109
+							<div class="form-group">
110
+								<label class="col-sm-4 control-label">{{Catégorie}}</label>
111
+								<div class="col-sm-6">
112
+									<?php
113
+									foreach (jeedom::getConfiguration('eqLogic:category') as $key => $value) {
114
+										echo '<label class="checkbox-inline">';
115
+										echo '<input type="checkbox" class="eqLogicAttr" data-l1key="category" data-l2key="' . $key . '" >' . $value['name'];
116
+										echo '</label>';
117
+									}
118
+									?>
119
+								</div>
120
+							</div>
121
+							<div class="form-group">
122
+								<label class="col-sm-4 control-label">{{Options}}</label>
123
+								<div class="col-sm-6">
124
+									<label class="checkbox-inline"><input type="checkbox" class="eqLogicAttr" data-l1key="isEnable" checked>{{Activer}}</label>
125
+									<label class="checkbox-inline"><input type="checkbox" class="eqLogicAttr" data-l1key="isVisible" checked>{{Visible}}</label>
126
+								</div>
127
+							</div>
128
+
129
+							<legend><i class="fas fa-cogs"></i> {{Paramètres spécifiques}}</legend>
130
+							<div class="form-group">
131
+								<label class="col-sm-4 control-label">{{Nom du paramètre n°1}}
132
+									<sup><i class="fas fa-question-circle tooltips" title="{{Renseignez le paramètre n°1 de l'équipement}}"></i></sup>
133
+								</label>
134
+								<div class="col-sm-6">
135
+									<input type="text" class="eqLogicAttr form-control" data-l1key="configuration" data-l2key="param1" placeholder="{{Paramètre n°1}}">
136
+								</div>
137
+							</div>
138
+							<div class="form-group">
139
+								<label class="col-sm-4 control-label"> {{Mot de passe}}
140
+									<sup><i class="fas fa-question-circle tooltips" title="{{Renseignez le mot de passe}}"></i></sup>
141
+								</label>
142
+								<div class="col-sm-6">
143
+									<input type="text" class="eqLogicAttr form-control inputPassword" data-l1key="configuration" data-l2key="password">
144
+								</div>
145
+							</div>
146
+							<!-- Exemple de champ de saisie du cron d'auto-actualisation avec assistant -->
147
+							<!-- La fonction cron de la classe du plugin doit contenir le code prévu pour que ce champ soit fonctionnel -->
148
+							<div class="form-group">
149
+								<label class="col-sm-4 control-label">{{Auto-actualisation}}
150
+									<sup><i class="fas fa-question-circle tooltips" title="{{Fréquence de rafraîchissement des commandes infos de l'équipement}}"></i></sup>
151
+								</label>
152
+								<div class="col-sm-6">
153
+									<div class="input-group">
154
+										<input type="text" class="eqLogicAttr form-control roundedLeft" data-l1key="configuration" data-l2key="autorefresh" placeholder="{{Cliquer sur ? pour afficher l'assistant cron}}">
155
+										<span class="input-group-btn">
156
+											<a class="btn btn-default cursor jeeHelper roundedRight" data-helper="cron" title="Assistant cron">
157
+												<i class="fas fa-question-circle"></i>
158
+											</a>
159
+										</span>
160
+									</div>
161
+								</div>
162
+							</div>
163
+						</div>
164
+
165
+						<!-- Partie droite de l'onglet "Équipement" -->
166
+						<!-- Affiche un champ de commentaire par défaut mais vous pouvez y mettre ce que vous voulez -->
167
+						<div class="col-lg-6">
168
+							<legend><i class="fas fa-info"></i> {{Informations}}</legend>
169
+							<div class="form-group">
170
+								<label class="col-sm-4 control-label">{{Description}}</label>
171
+								<div class="col-sm-6">
172
+									<textarea class="form-control eqLogicAttr autogrow" data-l1key="comment"></textarea>
173
+								</div>
174
+							</div>
175
+						</div>
176
+					</fieldset>
177
+				</form>
178
+			</div><!-- /.tabpanel #eqlogictab-->
179
+
180
+			<!-- Onglet des commandes de l'équipement -->
181
+			<div role="tabpanel" class="tab-pane" id="commandtab">
182
+				<a class="btn btn-default btn-sm pull-right cmdAction" data-action="add" style="margin-top:5px;"><i class="fas fa-plus-circle"></i> {{Ajouter une commande}}</a>
183
+				<br><br>
184
+				<div class="table-responsive">
185
+					<table id="table_cmd" class="table table-bordered table-condensed">
186
+						<thead>
187
+							<tr>
188
+								<th class="hidden-xs" style="min-width:50px;width:70px;">ID</th>
189
+								<th style="min-width:200px;width:350px;">{{Nom}}</th>
190
+								<th>{{Type}}</th>
191
+								<th style="min-width:260px;">{{Options}}</th>
192
+								<th>{{Etat}}</th>
193
+								<th style="min-width:80px;width:200px;">{{Actions}}</th>
194
+							</tr>
195
+						</thead>
196
+						<tbody>
197
+						</tbody>
198
+					</table>
199
+				</div>
200
+			</div><!-- /.tabpanel #commandtab-->
201
+
202
+		</div><!-- /.tab-content -->
203
+	</div><!-- /.eqLogic -->
204
+</div><!-- /.row row-overflow -->
205
+
206
+<!-- Inclusion du fichier javascript du plugin (dossier, nom_du_fichier, extension_du_fichier, id_du_plugin) -->
207
+<?php include_file('desktop', 'template', 'js', 'template');?>
208
+<!-- Inclusion du fichier javascript du core - NE PAS MODIFIER NI SUPPRIMER -->
209
+<?php include_file('core', 'plugin.template', 'js');?>
0 210
new file mode 100644
... ...
@@ -0,0 +1,30 @@
1
+# Changelog plugin template
2
+
3
+>**IMPORTANT**
4
+>
5
+>S'il n'y a pas d'information sur la mise à jour, c'est que celle-ci concerne uniquement de la mise à jour de documentation, de traduction ou de texte.
6
+
7
+# 19/01/2022
8
+
9
+- Optimisations V4.2
10
+
11
+# 20/11/2020
12
+
13
+- Présentation officielle V4
14
+- Ajouts d'éléments d'informations et de paramètres pour les commandes
15
+
16
+# 16/11/2020
17
+
18
+- version minimale Jeedom: 3.3.39 (dernière MAJ critique)
19
+
20
+# 04/11/2020
21
+
22
+- Nouvelle présentation de la liste des objets
23
+
24
+# 07/08/2020
25
+
26
+- Ajout de commentaires
27
+
28
+# 17/05/2020
29
+
30
+- Mise à jour de la documentation
0 31
new file mode 100644
... ...
@@ -0,0 +1,18 @@
1
+# Plugin template
2
+
3
+Ce "template de plugin" sert de base à la réalisation de plugins pour **Jeedom**.
4
+
5
+La documentation générale relative à la conception de plugin est consultable [ici](https://doc.jeedom.com/fr_FR/dev/).
6
+
7
+Dans le détail :   
8
+* [Utilisation du template de plugin](https://doc.jeedom.com/fr_FR/dev/plugin_template) : Le template de plugin est une base de plugin pour Jeedom qui doit être adaptée avec l'id de votre plugin et à laquelle il suffit d'ajouter vos propres fonctions.
9
+
10
+* [Fichier info.json](https://doc.jeedom.com/fr_FR/dev/structure_info_json) : Intégré depuis la version 3.0 de Jeedom, le fichier **info.json** est obligatoire pour le bon fonctionnement des plugins et leur bon déploiement sur le Market Jeedom.
11
+
12
+* [Icône du plugin](https://doc.jeedom.com/fr_FR/dev/Icone_de_plugin) : Afin de pouvoir être publié sur le Market Jeedom, tout plugin doit disposer d’une icône. Attention à ne pas utiliser le même code couleur que les icônes des plugins Jeedom officiels.
13
+
14
+* [Widget du plugin](https://doc.jeedom.com/fr_FR/dev/widget_plugin) : Présentation des différentes manières d'inclure des widgets personnalisés au plugin.
15
+
16
+* [Documentation du plugin](https://doc.jeedom.com/fr_FR/dev/documentation_plugin) : Présentation de la mise en place d'une documentation car un bon plugin n'est rien sans documentation adéquate.
17
+
18
+* [Publication du plugin](https://doc.jeedom.com/fr_FR/dev/publication_plugin) : Description des pré-requis indispensables à la publication du plugin.
0 19
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+Order allow,deny
2
+<Files ~ "\.(jpg|jpeg|png|gif|pdf|txt|bmp)$">
3
+   allow from all
4
+</Files>
5
+Deny from all
0 6
new file mode 100644
... ...
@@ -0,0 +1,56 @@
1
+<?php
2
+/* This file is part of Jeedom.
3
+*
4
+* Jeedom is free software: you can redistribute it and/or modify
5
+* it under the terms of the GNU General Public License as published by
6
+* the Free Software Foundation, either version 3 of the License, or
7
+* (at your option) any later version.
8
+*
9
+* Jeedom is distributed in the hope that it will be useful,
10
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+* GNU General Public License for more details.
13
+*
14
+* You should have received a copy of the GNU General Public License
15
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
16
+*/
17
+
18
+require_once dirname(__FILE__) . '/../../../core/php/core.inc.php';
19
+include_file('core', 'authentification', 'php');
20
+if (!isConnect()) {
21
+  include_file('desktop', '404', 'php');
22
+  die();
23
+}
24
+?>
25
+<form class="form-horizontal">
26
+  <fieldset>
27
+    <div class="form-group">
28
+      <label class="col-md-4 control-label">{{Global param 1}}
29
+        <sup><i class="fas fa-question-circle tooltips" title="{{Renseignez le paramètre 1 du plugin}}"></i></sup>
30
+      </label>
31
+      <div class="col-md-4">
32
+        <input class="configKey form-control" data-l1key="param1"/>
33
+      </div>
34
+    </div>
35
+    <div class="form-group">
36
+      <label class="col-md-4 control-label">{{Global param 2}}
37
+        <sup><i class="fas fa-question-circle tooltips" title="{{Renseignez le paramètre 2 du plugin}}"></i></sup>
38
+      </label>
39
+      <div class="col-md-4">
40
+        <input class="configKey form-control" data-l1key="param2"/>
41
+      </div>
42
+    </div>
43
+    <div class="form-group">
44
+      <label class="col-md-4 control-label">{{Global param 3}}
45
+        <sup><i class="fas fa-question-circle tooltips" title="{{Sélectionnez du paramètre 3 du plugin}}"></i></sup>
46
+      </label>
47
+      <div class="col-md-4">
48
+        <select class="configKey form-control" data-l1key="param3">
49
+          <option value=""></option>
50
+          <option value="value1">value1</option>
51
+          <option value="value2">value2</option>
52
+        </select>
53
+      </div>
54
+    </div>
55
+  </fieldset>
56
+</form>
0 57
new file mode 100644
... ...
@@ -0,0 +1,52 @@
1
+{
2
+	"id" : "template",
3
+	"name" : "Template",
4
+	"specialAttributes" : {
5
+		"object" : {
6
+			"toto" : {"name" : {"fr_FR" : "Plop je suis un attribut spécial"},"type" : "input"},
7
+			"toto2" : {"name" : {"fr_FR" : "Plop je suis un attribut spécial number"},"type" : "number"}
8
+		},
9
+		"user" : {
10
+			"toto" : {"name" : {"fr_FR" : "Plop je suis un attribut spécial"},"type" : "select","values" : [{"value" : "1", "name" : "valeur 1"},{"value" : "plop", "name" : "valeur plop"}]}
11
+		}
12
+	},
13
+	"description" : {
14
+		"fr_FR": "Template servant de base à la création de plugins pour Jeedom"
15
+	},
16
+	"licence" : "AGPL",
17
+	"author" : "Jeedom SAS",
18
+	"require" : "4.2.0",
19
+	"category" : "programming",
20
+	"hasDependency" : false,
21
+	"hasOwnDeamon" : false,
22
+	"maxDependancyInstallTime" : 0,
23
+	"changelog" : "https://jeedom.github.io/plugin-template/#language#/changelog",
24
+	"documentation" : "https://jeedom.github.io/plugin-template/#language#/",
25
+	"changelog_beta" : "https://jeedom.github.io/plugin-template/#language#/beta/changelog",
26
+	"documentation_beta" : "https://jeedom.github.io/plugin-template/#language#/beta/",
27
+	"link" : {
28
+		"forum":"Lien vers le forum",
29
+		"video" : "Lien vers une video"
30
+	},
31
+	"language": [
32
+		"fr_FR",
33
+		"en_US",
34
+		"es_ES",
35
+		"de_DE",
36
+		"ru_RU",
37
+		"id_ID",
38
+		"it_IT",
39
+		"ja_JP",
40
+		"pt_PT"
41
+	],
42
+	"compatibility": [
43
+		"miniplus",
44
+		"smart",
45
+		"rpi",
46
+		"docker",
47
+		"diy",
48
+		"mobile",
49
+		"v4",
50
+		"atlas"
51
+	]
52
+}
0 53
new file mode 100644
... ...
@@ -0,0 +1,30 @@
1
+<?php
2
+/* This file is part of Jeedom.
3
+*
4
+* Jeedom is free software: you can redistribute it and/or modify
5
+* it under the terms of the GNU General Public License as published by
6
+* the Free Software Foundation, either version 3 of the License, or
7
+* (at your option) any later version.
8
+*
9
+* Jeedom is distributed in the hope that it will be useful,
10
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+* GNU General Public License for more details.
13
+*
14
+* You should have received a copy of the GNU General Public License
15
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
16
+*/
17
+
18
+require_once dirname(__FILE__) . '/../../../core/php/core.inc.php';
19
+
20
+// Fonction exécutée automatiquement après l'installation du plugin
21
+function template_install() {
22
+}
23
+
24
+// Fonction exécutée automatiquement après la mise à jour du plugin
25
+function template_update() {
26
+}
27
+
28
+// Fonction exécutée automatiquement après la suppression du plugin
29
+function template_remove() {
30
+}
0 31
new file mode 100644
... ...
@@ -0,0 +1,16 @@
1
+{
2
+  "pre-install": {
3
+  },
4
+  "apt": {
5
+  },
6
+  "pip3": {
7
+  },
8
+  "npm": {
9
+  },
10
+  "yarn": {
11
+  },
12
+  "plugin": {
13
+  },
14
+  "post-install": {
15
+  }
16
+}
0 17
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+<?php
2
+
3
+/* This file is part of Jeedom.
4
+*
5
+* Jeedom is free software: you can redistribute it and/or modify
6
+* it under the terms of the GNU General Public License as published by
7
+* the Free Software Foundation, either version 3 of the License, or
8
+* (at your option) any later version.
9
+*
10
+* Jeedom is distributed in the hope that it will be useful,
11
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+* GNU General Public License for more details.
14
+*
15
+* You should have received a copy of the GNU General Public License
16
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
17
+*/
18
+
19
+require_once dirname(__FILE__) . '/../../../core/php/core.inc.php';
20
+
21
+// Fonction exécutée automatiquement avant la mise à jour du plugin
22
+function template_pre_update() {
23
+}
0 24
new file mode 100644
1 25
Binary files /dev/null and b/plugin_info/template_icon.png differ
2 26
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+Order allow,deny
2
+Deny from all
0 3
new file mode 100644
... ...
@@ -0,0 +1,142 @@
1
+# This file is part of Jeedom.
2
+#
3
+# Jeedom is free software: you can redistribute it and/or modify
4
+# it under the terms of the GNU General Public License as published by
5
+# the Free Software Foundation, either version 3 of the License, or
6
+# (at your option) any later version.
7
+# 
8
+# Jeedom is distributed in the hope that it will be useful,
9
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+# GNU General Public License for more details.
12
+# 
13
+# You should have received a copy of the GNU General Public License
14
+# along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+import logging
17
+import string
18
+import sys
19
+import os
20
+import time
21
+import datetime
22
+import traceback
23
+import re
24
+import signal
25
+from optparse import OptionParser
26
+from os.path import join
27
+import json
28
+import argparse
29
+
30
+try:
31
+	from jeedom.jeedom import *
32
+except ImportError:
33
+	print("Error: importing module jeedom.jeedom")
34
+	sys.exit(1)
35
+
36
+def read_socket():
37
+	global JEEDOM_SOCKET_MESSAGE
38
+	if not JEEDOM_SOCKET_MESSAGE.empty():
39
+		logging.debug("Message received in socket JEEDOM_SOCKET_MESSAGE")
40
+		message = json.loads(jeedom_utils.stripped(JEEDOM_SOCKET_MESSAGE.get()))
41
+		if message['apikey'] != _apikey:
42
+			logging.error("Invalid apikey from socket : " + str(message))
43
+			return
44
+		try:
45
+			print ('read')
46
+		except Exception, e:
47
+			logging.error('Send command to demon error : '+str(e))
48
+
49
+def listen():
50
+	jeedom_socket.open()
51
+	try:
52
+		while 1:
53
+			time.sleep(0.5)
54
+			read_socket()
55
+	except KeyboardInterrupt:
56
+		shutdown()
57
+
58
+# ----------------------------------------------------------------------------
59
+
60
+def handler(signum=None, frame=None):
61
+	logging.debug("Signal %i caught, exiting..." % int(signum))
62
+	shutdown()
63
+
64
+def shutdown():
65
+	logging.debug("Shutdown")
66
+	logging.debug("Removing PID file " + str(_pidfile))
67
+	try:
68
+		os.remove(_pidfile)
69
+	except:
70
+		pass
71
+	try:
72
+		jeedom_socket.close()
73
+	except:
74
+		pass
75
+	try:
76
+		jeedom_serial.close()
77
+	except:
78
+		pass
79
+	logging.debug("Exit 0")
80
+	sys.stdout.flush()
81
+	os._exit(0)
82
+
83
+# ----------------------------------------------------------------------------
84
+
85
+_log_level = "error"
86
+_socket_port = 55009
87
+_socket_host = 'localhost'
88
+_device = 'auto'
89
+_pidfile = '/tmp/demond.pid'
90
+_apikey = ''
91
+_callback = ''
92
+_cycle = 0.3
93
+
94
+parser = argparse.ArgumentParser(
95
+    description='Desmond Daemon for Jeedom plugin')
96
+parser.add_argument("--device", help="Device", type=str)
97
+parser.add_argument("--loglevel", help="Log Level for the daemon", type=str)
98
+parser.add_argument("--callback", help="Callback", type=str)
99
+parser.add_argument("--apikey", help="Apikey", type=str)
100
+parser.add_argument("--cycle", help="Cycle to send event", type=str)
101
+parser.add_argument("--pid", help="Pid file", type=str)
102
+parser.add_argument("--socketport", help="Port for Zigbee server", type=str)
103
+args = parser.parse_args()
104
+
105
+if args.device:
106
+	_device = args.device
107
+if args.loglevel:
108
+    _log_level = args.loglevel
109
+if args.callback:
110
+    _callback = args.callback
111
+if args.apikey:
112
+    _apikey = args.apikey
113
+if args.pid:
114
+    _pidfile = args.pid
115
+if args.cycle:
116
+    _cycle = float(args.cycle)
117
+if args.socketport:
118
+	_socketport = args.socketport
119
+		
120
+_socket_port = int(_socket_port)
121
+
122
+jeedom_utils.set_log_level(_log_level)
123
+
124
+logging.info('Start demond')
125
+logging.info('Log level : '+str(_log_level))
126
+logging.info('Socket port : '+str(_socket_port))
127
+logging.info('Socket host : '+str(_socket_host))
128
+logging.info('PID file : '+str(_pidfile))
129
+logging.info('Apikey : '+str(_apikey))
130
+logging.info('Device : '+str(_device))
131
+
132
+signal.signal(signal.SIGINT, handler)
133
+signal.signal(signal.SIGTERM, handler)	
134
+
135
+try:
136
+	jeedom_utils.write_pid(str(_pidfile))
137
+	jeedom_socket = jeedom_socket(port=_socket_port,address=_socket_host)
138
+	listen()
139
+except Exception as e:
140
+	logging.error('Fatal error : '+str(e))
141
+	logging.info(traceback.format_exc())
142
+	shutdown()
0 143
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+# This file is part of Jeedom.
2
+#
3
+# Jeedom is free software: you can redistribute it and/or modify
4
+# it under the terms of the GNU General Public License as published by
5
+# the Free Software Foundation, either version 3 of the License, or
6
+# (at your option) any later version.
7
+#
8
+# Jeedom is distributed in the hope that it will be useful,
9
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+# GNU General Public License for more details.
12
+#
13
+# You should have received a copy of the GNU General Public License
14
+# along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
15
+#
0 16
new file mode 100644
... ...
@@ -0,0 +1,184 @@
1
+/* This file is part of Jeedom.
2
+*
3
+* Jeedom is free software: you can redistribute it and/or modify
4
+* it under the terms of the GNU General Public License as published by
5
+* the Free Software Foundation, either version 3 of the License, or
6
+* (at your option) any later version.
7
+*
8
+* Jeedom is distributed in the hope that it will be useful,
9
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+* GNU General Public License for more details.
12
+*
13
+* You should have received a copy of the GNU General Public License
14
+* along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
15
+*/
16
+
17
+const request = require('request');
18
+var express = require('express');
19
+
20
+var Jeedom = {}
21
+Jeedom.log = {}
22
+Jeedom.com = {}
23
+Jeedom.http = {}
24
+
25
+/***************************ARGS*******************************/
26
+
27
+Jeedom.getArgs = function() {
28
+  var result = {}
29
+  var args = process.argv.slice(2,process.argv.length);
30
+  for (var i = 0, len = args.length; i < len; i++) {
31
+    if (args[i].slice(0,2) === '--') {
32
+      result[args[i].slice(2,args[i].length)] = args[i + 1]
33
+    }
34
+  }
35
+  return result
36
+}
37
+
38
+/***************************LOGS*******************************/
39
+
40
+Jeedom.log.setLevel = function(_level){
41
+  var convert = {debug  : 0,info : 10,notice : 20,warning : 30,error : 40,critical : 50,none : 60}
42
+  Jeedom.log.level = convert[_level]
43
+}
44
+
45
+Jeedom.log.debug  = function(_log){
46
+  if(Jeedom.log.level > 0){
47
+    return;
48
+  }
49
+  console.log('['+(new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''))+'][DEBUG] : '+_log)
50
+}
51
+
52
+Jeedom.log.info  = function(_log){
53
+  if(Jeedom.log.level > 10){
54
+    return;
55
+  }
56
+  console.log('['+(new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''))+'][INFO] : '+_log)
57
+}
58
+
59
+Jeedom.log.error  = function(_log){
60
+  if(Jeedom.log.level > 40){
61
+    return;
62
+  }
63
+  console.log('['+(new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''))+'][ERROR] : '+_log)
64
+}
65
+
66
+/***************************PID*******************************/
67
+
68
+Jeedom.write_pid = function(_file){
69
+  var fs = require('fs');
70
+  fs.writeFile(_file, process.pid.toString(), function(err) {
71
+    if(err) {
72
+      Jeedom.log.error("Can't write pid file : "+err);
73
+      process.exit()
74
+    }
75
+  });
76
+}
77
+
78
+/***************************COM*******************************/
79
+
80
+Jeedom.isObject = function(item) {
81
+  return (item && typeof item === 'object' && !Array.isArray(item));
82
+}
83
+
84
+Jeedom.mergeDeep = function(target, ...sources) {
85
+  if (!sources.length) return target;
86
+  const source = sources.shift();
87
+  if (Jeedom.isObject(target) && Jeedom.isObject(source)) {
88
+    for (const key in source) {
89
+      if (Jeedom.isObject(source[key])) {
90
+        if (!target[key]) Object.assign(target, { [key]: {} });
91
+        Jeedom.mergeDeep(target[key], source[key]);
92
+      } else {
93
+        Object.assign(target, { [key]: source[key] });
94
+      }
95
+    }
96
+  }
97
+  return Jeedom.mergeDeep(target, ...sources);
98
+}
99
+
100
+Jeedom.com.config = function(_apikey,_callback,_cycle){
101
+  Jeedom.com.apikey = _apikey;
102
+  Jeedom.com.callback = _callback;
103
+  Jeedom.com.cycle = _cycle;
104
+  Jeedom.com.changes = {};
105
+  if(Jeedom.com.cycle > 0){
106
+    setInterval(function() {
107
+      if(Object.keys(Jeedom.com.changes).length > 0){
108
+        Jeedom.com.send_change_immediate(Jeedom.com.changes);
109
+        Jeedom.com.changes = {};
110
+      }
111
+    }, Jeedom.com.cycle * 1000);
112
+  }
113
+}
114
+
115
+Jeedom.com.add_changes = function(_key,_value){
116
+  if (_key.indexOf('::') != -1){
117
+    tmp_changes = {}
118
+    var changes = _value
119
+    var keys = _key.split('::').reverse();
120
+    for (var k in keys){
121
+      if (typeof tmp_changes[keys[k]] == 'undefined'){
122
+        tmp_changes[keys[k]] = {}
123
+      }
124
+      tmp_changes[keys[k]] = changes
125
+      changes = tmp_changes
126
+      tmp_changes = {}
127
+    }
128
+    if (Jeedom.com.cycle <= 0){
129
+      Jeedom.com.send_change_immediate(changes)
130
+    }else{
131
+      Jeedom.com.changes = Jeedom.mergeDeep(Jeedom.com.changes,changes)
132
+    }
133
+  } else{
134
+    if (Jeedom.com.cycle <= 0){
135
+      Jeedom.com.send_change_immediate({_key:_value})
136
+    }else{
137
+      Jeedom.com.changes[_key] = _value
138
+    }
139
+  }
140
+}
141
+
142
+Jeedom.com.send_change_immediate = function(_changes){
143
+  Jeedom.log.debug('Send data to jeedom : '+JSON.stringify(_changes));
144
+  request.post({url:Jeedom.com.callback+'?apikey='+Jeedom.com.apikey, json: _changes}, function(error, response, body){
145
+    if(response.statusCode != 200){
146
+      Jeedom.log.error('Error on send to jeedom : '+JSON.stringify(error));
147
+    }
148
+  })
149
+}
150
+
151
+Jeedom.com.test = function(_changes){
152
+  request.post({url:Jeedom.com.callback+'?apikey='+Jeedom.com.apikey, json: {}}, function(error, response, body){
153
+    if(response.statusCode != 200){
154
+      Jeedom.log.error('Callback error.Please check your network configuration page : '+JSON.stringify(error));
155
+      process.exit();
156
+    }
157
+  })
158
+}
159
+
160
+/***************************HTTP SERVER*******************************/
161
+
162
+Jeedom.http.config = function(_port,_apikey){
163
+  Jeedom.http.apikey = _apikey;
164
+  Jeedom.http.app = express();
165
+  Jeedom.http.app.get('/', function(req, res) {
166
+    res.setHeader('Content-Type', 'text/plain');
167
+    res.status(404).send('Not found');
168
+  });
169
+  Jeedom.http.app.listen(_port,'127.0.0.1', function() {
170
+    Jeedom.log.debug('HTTP listen on 127.0.0.1 port : '+_port+' started');
171
+  });
172
+}
173
+
174
+Jeedom.http.checkApikey = function(_req){
175
+  return (_req.query.apikey == Jeedom.http.apikey)
176
+}
177
+
178
+/***************************EXPORTS*******************************/
179
+
180
+exports.getArgs = Jeedom.getArgs;
181
+exports.log = Jeedom.log;
182
+exports.write_pid = Jeedom.write_pid;
183
+exports.com = Jeedom.com;
184
+exports.http = Jeedom.http;
0 185
new file mode 100644
... ...
@@ -0,0 +1,349 @@
1
+# This file is part of Jeedom.
2
+#
3
+# Jeedom is free software: you can redistribute it and/or modify
4
+# it under the terms of the GNU General Public License as published by
5
+# the Free Software Foundation, either version 3 of the License, or
6
+# (at your option) any later version.
7
+#
8
+# Jeedom is distributed in the hope that it will be useful,
9
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+# GNU General Public License for more details.
12
+#
13
+# You should have received a copy of the GNU General Public License
14
+# along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
15
+#
16
+
17
+import time
18
+import logging
19
+import threading
20
+import requests
21
+import datetime
22
+try:
23
+    from collections.abc import Mapping
24
+except ImportError:
25
+    from collections import Mapping
26
+import serial
27
+import os
28
+from os.path import join
29
+import socket
30
+from queue import Queue
31
+import socketserver
32
+from socketserver import (TCPServer, StreamRequestHandler)
33
+import signal
34
+import unicodedata
35
+import pyudev
36
+
37
+# ------------------------------------------------------------------------------
38
+
39
+class jeedom_com():
40
+	def __init__(self,apikey = '',url = '',cycle = 0.5,retry = 3):
41
+		self.apikey = apikey
42
+		self.url = url
43
+		self.cycle = cycle
44
+		self.retry = retry
45
+		self.changes = {}
46
+		if cycle > 0 :
47
+			self.send_changes_async()
48
+		logging.info('Init request module v%s' % (str(requests.__version__),))
49
+
50
+	def send_changes_async(self):
51
+		try:
52
+			if len(self.changes) == 0:
53
+				resend_changes = threading.Timer(self.cycle, self.send_changes_async)
54
+				resend_changes.start()
55
+				return
56
+			start_time = datetime.datetime.now()
57
+			changes = self.changes
58
+			self.changes = {}
59
+			logging.info('Send to jeedom : '+str(changes))
60
+			i=0
61
+			while i < self.retry:
62
+				try:
63
+					r = requests.post(self.url + '?apikey=' + self.apikey, json=changes, timeout=(0.5, 120), verify=False)
64
+					if r.status_code == requests.codes.ok:
65
+						break
66
+				except Exception as error:
67
+					logging.error('Error on send request to jeedom ' + str(error)+' retry : '+str(i)+'/'+str(self.retry))
68
+				i = i + 1
69
+			if r.status_code != requests.codes.ok:
70
+				logging.error('Error on send request to jeedom, return code %s' % (str(r.status_code),))
71
+			dt = datetime.datetime.now() - start_time
72
+			ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
73
+			timer_duration = self.cycle - ms
74
+			if timer_duration < 0.1 :
75
+				timer_duration = 0.1
76
+			if timer_duration > self.cycle:
77
+				timer_duration = self.cycle
78
+			resend_changes = threading.Timer(timer_duration, self.send_changes_async)
79
+			resend_changes.start()
80
+		except Exception as error:
81
+			logging.error('Critical error on  send_changes_async %s' % (str(error),))
82
+			resend_changes = threading.Timer(self.cycle, self.send_changes_async)
83
+			resend_changes.start()
84
+
85
+	def add_changes(self,key,value):
86
+		if key.find('::') != -1:
87
+			tmp_changes = {}
88
+			changes = value
89
+			for k in reversed(key.split('::')):
90
+				if k not in tmp_changes:
91
+					tmp_changes[k] = {}
92
+				tmp_changes[k] = changes
93
+				changes = tmp_changes
94
+				tmp_changes = {}
95
+			if self.cycle <= 0:
96
+				self.send_change_immediate(changes)
97
+			else:
98
+				self.merge_dict(self.changes,changes)
99
+		else:
100
+			if self.cycle <= 0:
101
+				self.send_change_immediate({key:value})
102
+			else:
103
+				self.changes[key] = value
104
+
105
+	def send_change_immediate(self,change):
106
+		threading.Thread( target=self.thread_change,args=(change,)).start()
107
+
108
+	def thread_change(self,change):
109
+		logging.info('Send to jeedom :  %s' % (str(change),))
110
+		i=0
111
+		while i < self.retry:
112
+			try:
113
+				r = requests.post(self.url + '?apikey=' + self.apikey, json=change, timeout=(0.5, 120), verify=False)
114
+				if r.status_code == requests.codes.ok:
115
+					break
116
+			except Exception as error:
117
+				logging.error('Error on send request to jeedom ' + str(error)+' retry : '+str(i)+'/'+str(self.retry))
118
+			i = i + 1
119
+
120
+	def set_change(self,changes):
121
+		self.changes = changes
122
+
123
+	def get_change(self):
124
+		return self.changes
125
+
126
+	def merge_dict(self,d1, d2):
127
+		for k,v2 in d2.items():
128
+			v1 = d1.get(k) # returns None if v1 has no value for this key
129
+			if isinstance(v1, Mapping) and isinstance(v2, Mapping):
130
+				self.merge_dict(v1, v2)
131
+			else:
132
+				d1[k] = v2
133
+
134
+	def test(self):
135
+		try:
136
+			response = requests.get(self.url + '?apikey=' + self.apikey, verify=False)
137
+			if response.status_code != requests.codes.ok:
138
+				logging.error('Callback error: %s %s. Please check your network configuration page'% (response.status.code, response.status.message,))
139
+				return False
140
+		except Exception as e:
141
+			logging.error('Callback result as a unknown error: %s. Please check your network configuration page'% (e.message,))
142
+			return False
143
+		return True
144
+
145
+# ------------------------------------------------------------------------------
146
+
147
+class jeedom_utils():
148
+
149
+	@staticmethod
150
+	def convert_log_level(level = 'error'):
151
+		LEVELS = {'debug': logging.DEBUG,
152
+		  'info': logging.INFO,
153
+		  'notice': logging.WARNING,
154
+		  'warning': logging.WARNING,
155
+		  'error': logging.ERROR,
156
+		  'critical': logging.CRITICAL,
157
+		  'none': logging.CRITICAL}
158
+		return LEVELS.get(level, logging.CRITICAL)
159
+
160
+	@staticmethod
161
+	def set_log_level(level = 'error'):
162
+		FORMAT = '[%(asctime)-15s][%(levelname)s] : %(message)s'
163
+		logging.basicConfig(level=jeedom_utils.convert_log_level(level),format=FORMAT, datefmt="%Y-%m-%d %H:%M:%S")
164
+
165
+	@staticmethod
166
+	def find_tty_usb(idVendor, idProduct, product = None):
167
+		context = pyudev.Context()
168
+		for device in context.list_devices(subsystem='tty'):
169
+			if 'ID_VENDOR' not in device:
170
+				continue
171
+			if device['ID_VENDOR_ID'] != idVendor:
172
+				continue
173
+			if device['ID_MODEL_ID'] != idProduct:
174
+				continue
175
+			if product is not None:
176
+				if 'ID_VENDOR' not in device or device['ID_VENDOR'].lower().find(product.lower()) == -1 :
177
+					continue
178
+			return str(device.device_node)
179
+		return None
180
+
181
+	@staticmethod
182
+	def stripped(str):
183
+		return "".join([i for i in str if i in range(32, 127)])
184
+
185
+	@staticmethod
186
+	def ByteToHex( byteStr ):
187
+		return byteStr.hex()
188
+
189
+	@staticmethod
190
+	def dec2bin(x, width=8):
191
+		return ''.join(str((x>>i)&1) for i in xrange(width-1,-1,-1))
192
+
193
+	@staticmethod
194
+	def dec2hex(dec):
195
+		if dec is None:
196
+			return '0x00'
197
+		return "0x{:02X}".format(dec)
198
+
199
+	@staticmethod
200
+	def testBit(int_type, offset):
201
+		mask = 1 << offset
202
+		return(int_type & mask)
203
+
204
+	@staticmethod
205
+	def clearBit(int_type, offset):
206
+		mask = ~(1 << offset)
207
+		return(int_type & mask)
208
+
209
+	@staticmethod
210
+	def split_len(seq, length):
211
+		return [seq[i:i+length] for i in range(0, len(seq), length)]
212
+
213
+	@staticmethod
214
+	def write_pid(path):
215
+		pid = str(os.getpid())
216
+		logging.info("Writing PID " + pid + " to " + str(path))
217
+		open(path, 'w').write("%s\n" % pid)
218
+
219
+	@staticmethod
220
+	def remove_accents(input_str):
221
+		nkfd_form = unicodedata.normalize('NFKD', unicode(input_str))
222
+		return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
223
+
224
+	@staticmethod
225
+	def printHex(hex):
226
+		return ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)])
227
+
228
+# ------------------------------------------------------------------------------
229
+
230
+class jeedom_serial():
231
+
232
+	def __init__(self,device = '',rate = '',timeout = 9,rtscts = True,xonxoff=False):
233
+		self.device = device
234
+		self.rate = rate
235
+		self.timeout = timeout
236
+		self.port = None
237
+		self.rtscts = rtscts
238
+		self.xonxoff = xonxoff
239
+		logging.info('Init serial module v%s' % (str(serial.VERSION),))
240
+
241
+	def open(self):
242
+		if self.device:
243
+			logging.info("Open serial port on device: " + str(self.device)+', rate '+str(self.rate)+', timeout : '+str(self.timeout))
244
+		else:
245
+			logging.error("Device name missing.")
246
+			return False
247
+		logging.info("Open Serialport")
248
+		try:
249
+			self.port = serial.Serial(
250
+			self.device,
251
+			self.rate,
252
+			timeout=self.timeout,
253
+			rtscts=self.rtscts,
254
+			xonxoff=self.xonxoff,
255
+			parity=serial.PARITY_NONE,
256
+			stopbits=serial.STOPBITS_ONE
257
+			)
258
+		except serial.SerialException as e:
259
+			logging.error("Error: Failed to connect on device " + self.device + " Details : " + str(e))
260
+			return False
261
+		if not self.port.isOpen():
262
+			self.port.open()
263
+		self.flushOutput()
264
+		self.flushInput()
265
+		return True
266
+
267
+	def close(self):
268
+		logging.info("Close serial port")
269
+		try:
270
+			self.port.close()
271
+			logging.info("Serial port closed")
272
+			return True
273
+		except:
274
+			logging.error("Failed to close the serial port (" + self.device + ")")
275
+			return False
276
+
277
+	def write(self,data):
278
+		logging.info("Write data to serial port : "+str(jeedom_utils.ByteToHex(data)))
279
+		self.port.write(data)
280
+
281
+	def flushOutput(self,):
282
+		logging.info("flushOutput serial port ")
283
+		self.port.flushOutput()
284
+
285
+	def flushInput(self):
286
+		logging.info("flushInput serial port ")
287
+		self.port.flushInput()
288
+
289
+	def read(self):
290
+		if self.port.inWaiting() != 0:
291
+			return self.port.read()
292
+		return None
293
+
294
+	def readbytes(self,number):
295
+		buf = b''
296
+		for i in range(number):
297
+			try:
298
+				byte = self.port.read()
299
+			except IOError as e:
300
+				logging.error("Error: " + str(e))
301
+			except OSError as e:
302
+				logging.error("Error: " + str(e))
303
+			buf += byte
304
+		return buf
305
+
306
+# ------------------------------------------------------------------------------
307
+
308
+JEEDOM_SOCKET_MESSAGE = Queue()
309
+
310
+class jeedom_socket_handler(StreamRequestHandler):
311
+	def handle(self):
312
+		global JEEDOM_SOCKET_MESSAGE
313
+		logging.info("Client connected to [%s:%d]" % self.client_address)
314
+		lg = self.rfile.readline()
315
+		JEEDOM_SOCKET_MESSAGE.put(lg)
316
+		logging.info("Message read from socket: " + str(lg.strip()))
317
+		self.netAdapterClientConnected = False
318
+		logging.info("Client disconnected from [%s:%d]" % self.client_address)
319
+
320
+class jeedom_socket():
321
+
322
+	def __init__(self,address='localhost', port=55000):
323
+		self.address = address
324
+		self.port = port
325
+		socketserver.TCPServer.allow_reuse_address = True
326
+
327
+	def open(self):
328
+		self.netAdapter = TCPServer((self.address, self.port), jeedom_socket_handler)
329
+		if self.netAdapter:
330
+			logging.info("Socket interface started")
331
+			threading.Thread(target=self.loopNetServer, args=()).start()
332
+		else:
333
+			logging.info("Cannot start socket interface")
334
+
335
+	def loopNetServer(self):
336
+		logging.info("LoopNetServer Thread started")
337
+		logging.info("Listening on: [%s:%d]" % (self.address, self.port))
338
+		self.netAdapter.serve_forever()
339
+		logging.info("LoopNetServer Thread stopped")
340
+
341
+	def close(self):
342
+		self.netAdapter.shutdown()
343
+
344
+	def getMessage(self):
345
+		return self.message
346
+
347
+# ------------------------------------------------------------------------------
348
+# END
349
+# ------------------------------------------------------------------------------