Bonjour,
J'ai fait évoluer le code du plugin pour répondre à mes besoins. Je m'explique:
En effet je souhaitais, pouvoir ré-ouvrir le volets si certaines conditions n'était pas réunies. Par exemple, aujourd'hui, je ferme mes velux si la température extérieure dépasse 23 °C et la température intérieure dépasse 23 °C et l'altitude du soleil > 5. Je veux donc que si une des 2 températures est <= à 23°C ou que le soleil est trop bas, les velux s'ouvrent.
Pour cela j'ai mis en place un nouveau critère, qui permet de tester une condition à l'inverse et donc si celle-ci est vrai de ré-ouvrir le volet pendant que le soleil est dans la fenêtre.
De même cela fonctionnera l’hiver pour refermer le volet si la condition inverse est vrai.
Toutes les autres conditions marquées "condition normale' continuent à être testées normalement et vérifiées lors du contrôle pour la ré-ouverture avec le soleil dans la fenêtre.
Le test inversé n'est pas réalisé dans le cas jour/nuit, et toutes les conditions sont testées de manière normale s'il s'agit du test de fermeture quand le soleil arrive dans la fenêtre.
Voici un exemple de configuration pour mes velux
- condition plugin volet.JPG (356.37 Kio) Consulté 2264 fois
Et voici le code modifié:
Volets/desktop/js/Volets.js
Code : Tout sélectionner
var map;
var DroitLatLng=new Object();
var CentreLatLng=new Object();
var GaucheLatLng=new Object();
$("#table_cmd").sortable({axis: "y", cursor: "move", items: ".cmd", placeholder: "ui-state-highlight", tolerance: "intersect", forcePlaceholderSize: true});
$("#table_condition").sortable({axis: "y", cursor: "move", items: ".ConditionGroup", placeholder: "ui-state-highlight", tolerance: "intersect", forcePlaceholderSize: true});
$("#table_ouverture").sortable({axis: "y", cursor: "move", items: ".ActionGroup", placeholder: "ui-state-highlight", tolerance: "intersect", forcePlaceholderSize: true});
$("#table_fermeture").sortable({axis: "y", cursor: "move", items: ".ActionGroup", placeholder: "ui-state-highlight", tolerance: "intersect", forcePlaceholderSize: true});
$('body').on('change','.eqLogicAttr[data-l1key=configuration][data-l2key=isRandom]',function(){
if($(this).is(':checked'))
$('.Presence').show();
else
$('.Presence').hide();
});
$('body').on('change','.eqLogicAttr[data-l1key=configuration][data-l2key=heliotrope]',function(){
$('#MyMap').html('');
$.ajax({
type: 'POST',
async: false,
url: 'plugins/Volets/core/ajax/Volets.ajax.php',
data:{
action: 'getInformation',
heliotrope:$(this).val(),
},
dataType: 'json',
global: false,
error: function(request, status, error) {},
success: function(data) {
if (!data.result)
$('#div_alert').showAlert({message: 'Aucun message reçu', level: 'error'});
if (typeof(data.result.geoloc) !== 'undefined') {
var center=data.result.geoloc.configuration.coordinate.split(",");
CentreLatLng.lat=parseFloat(center[0]);
CentreLatLng.lng=parseFloat(center[1]);
map = new ol.Map({
view: new ol.View({
center: ol.proj.fromLonLat([CentreLatLng.lng,CentreLatLng.lat]),
zoom: 10
}),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'MyMap'
});
}
}
});
});
function saveEqLogic(_eqLogic) {
_eqLogic.configuration.condition=new Object();
_eqLogic.configuration.action=new Object();
var ConditionArray= new Array();
var OpenArray= new Array();
var CloseArray= new Array();
$('#conditiontab .ConditionGroup').each(function( index ) {
ConditionArray.push($(this).getValues('.expressionAttr')[0])
});
$('#ouverturetab .ActionGroup').each(function( index ) {
OpenArray.push($(this).getValues('.expressionAttr')[0])
});
$('#fermeturetab .ActionGroup').each(function( index ) {
CloseArray.push($(this).getValues('.expressionAttr')[0])
});
_eqLogic.configuration.condition=ConditionArray;
_eqLogic.configuration.action.open=OpenArray;
_eqLogic.configuration.action.close=CloseArray;
return _eqLogic;
}
function printEqLogic(_eqLogic) {
$('.ConditionGroup').remove();
$('.ActionGroup').remove();
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Droite]').val(JSON.stringify(_eqLogic.configuration.Droite));
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Centre]').val(JSON.stringify(_eqLogic.configuration.Centre));
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Gauche]').val(JSON.stringify(_eqLogic.configuration.Gauche));
if (typeof(_eqLogic.configuration.heliotrope) !== 'undefined' && _eqLogic.configuration.heliotrope!='')
TraceMapZone(_eqLogic);
if (typeof(_eqLogic.configuration.condition) !== 'undefined') {
for(var index in _eqLogic.configuration.condition) {
if( (typeof _eqLogic.configuration.condition[index] === "object") && (_eqLogic.configuration.condition[index] !== null) )
addCondition(_eqLogic.configuration.condition[index],$('#conditiontab').find('table tbody'));
}
}
if (typeof(_eqLogic.configuration.action) !== 'undefined') {
if (typeof(_eqLogic.configuration.action.open) !== 'undefined') {
for(var index in _eqLogic.configuration.action.open) {
if( (typeof _eqLogic.configuration.action.open[index] === "object") && (_eqLogic.configuration.action.open[index] !== null) )
addAction(_eqLogic.configuration.action.open[index],$('#ouverturetab').find('table tbody'));
}
}
if (typeof(_eqLogic.configuration.action.close) !== 'undefined') {
for(var index in _eqLogic.configuration.action.close) {
if( (typeof _eqLogic.configuration.action.close[index] === "object") && (_eqLogic.configuration.action.close[index] !== null) )
addAction(_eqLogic.configuration.action.close[index],$('#fermeturetab').find('table tbody'));
}
}
}
}
function TraceMapZone(_zone){
DroitLatLng.lat=CentreLatLng.lat;
DroitLatLng.lng=CentreLatLng.lng- (1 / 3600);
GaucheLatLng.lat=CentreLatLng.lat;
GaucheLatLng.lng=CentreLatLng.lng+ (1 / 3600);
if (typeof(_zone.configuration.Droite) !== 'undefined' && _zone.configuration.Droite != "") {
if (typeof(_zone.configuration.Droite.lat) !== 'undefined' && _zone.configuration.Droite.lat != "" )
DroitLatLng.lat=parseFloat(_zone.configuration.Droite.lat);
if (typeof(_zone.configuration.Droite.lng) !== 'undefined' && _zone.configuration.Droite.lng != "" )
DroitLatLng.lng=parseFloat(_zone.configuration.Droite.lng);
}
if (typeof(_zone.configuration.Gauche) !== 'undefined' && _zone.configuration.Gauche != "") {
if (typeof(_zone.configuration.Gauche.lat) !== 'undefined' && _zone.configuration.Gauche.lat != "" )
GaucheLatLng.lat=parseFloat(_zone.configuration.Gauche.lat);
if (typeof(_zone.configuration.Gauche.lng) !== 'undefined' && _zone.configuration.Gauche.lng != "" )
GaucheLatLng.lng=parseFloat(_zone.configuration.Gauche.lng);
}
if (typeof(_zone.configuration.Centre) !== 'undefined' && _zone.configuration.Centre != "") {
if (typeof(_zone.configuration.Centre.lat) !== 'undefined' && _zone.configuration.Centre.lat != "" )
CentreLatLng.lat=parseFloat(_zone.configuration.Centre.lat);
if (typeof(_zone.configuration.Centre.lng) !== 'undefined' && _zone.configuration.Centre.lng != "" )
CentreLatLng.lng=parseFloat(_zone.configuration.Centre.lng);
}
var features = [];
var PolylineDroite = new ol.geom.Polygon([[[CentreLatLng.lng,CentreLatLng.lat], [DroitLatLng.lng,DroitLatLng.lat]]]);
PolylineDroite.transform('EPSG:4326', 'EPSG:3857');
features.push(new ol.Feature(PolylineDroite));
var PolylineGauche = new ol.geom.Polygon([[[CentreLatLng.lng,CentreLatLng.lat], [GaucheLatLng.lng,GaucheLatLng.lat]]]);
PolylineGauche.transform('EPSG:4326', 'EPSG:3857');
features.push(new ol.Feature(PolylineGauche));
var Droit = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([DroitLatLng.lng,DroitLatLng.lat], 'EPSG:4326', 'EPSG:3857'))
});
Droit.setStyle([
new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: '#000'
}),
fill: new ol.style.Fill({
color: 'rgba(255,255,255,0.4)'
}),
}),
text: new ol.style.Text({
text: _zone.name + " - Droite vue extérieur",
offsetY: -25,
fill: new ol.style.Fill({
color: '#fff'
})
})
})
]);
map.addInteraction(new ol.interaction.Modify({
features: new ol.Collection([Droit]),
style: null
}));
Droit.on('change',function(){
var coord = this.getGeometry().getCoordinates();
coord = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
DroitLatLng.lat= coord[1];
DroitLatLng.lng= coord[0];
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Droite]').val(JSON.stringify(DroitLatLng));
PolylineDroite.setCoordinates([[[CentreLatLng.lng,CentreLatLng.lat], [DroitLatLng.lng,DroitLatLng.lat]]]);
PolylineDroite.transform('EPSG:4326', 'EPSG:3857');
},Droit);
features.push(Droit);
var Centre = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([CentreLatLng.lng,CentreLatLng.lat], 'EPSG:4326', 'EPSG:3857'))
});
map.addInteraction(new ol.interaction.Modify({
features: new ol.Collection([Centre]),
style: null
}));
Centre.on('change',function(){
var coord = this.getGeometry().getCoordinates();
coord = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
CentreLatLng.lat= coord[1];
CentreLatLng.lng= coord[0];
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Centre]').val(JSON.stringify(CentreLatLng));
PolylineDroite.setCoordinates([[[CentreLatLng.lng,CentreLatLng.lat], [DroitLatLng.lng,DroitLatLng.lat]]]);
PolylineDroite.transform('EPSG:4326', 'EPSG:3857');
PolylineGauche.setCoordinates([[[CentreLatLng.lng,CentreLatLng.lat], [GaucheLatLng.lng,GaucheLatLng.lat]]]);
PolylineGauche.transform('EPSG:4326', 'EPSG:3857');
},Centre);
features.push(Centre);
var Gauche = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([GaucheLatLng.lng,GaucheLatLng.lat], 'EPSG:4326', 'EPSG:3857')),
style: new ol.style.Style({text:new ol.style.Text({text: _zone.name + " - Gauche vue extérieur"})})
});
Gauche.setStyle([
new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: '#000'
}),
fill: new ol.style.Fill({
color: 'rgba(255,255,255,0.4)'
}),
}),
text: new ol.style.Text({
text: _zone.name + " - Gauche vue extérieur",
offsetY: -25,
fill: new ol.style.Fill({
color: '#fff'
})
})
})
]);
map.addInteraction(new ol.interaction.Modify({
features: new ol.Collection([Gauche]),
style: null
}));
Gauche.on('change',function(){
var coord = this.getGeometry().getCoordinates();
coord = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
GaucheLatLng.lat= coord[1];
GaucheLatLng.lng= coord[0];
$('.eqLogicAttr[data-l1key=configuration][data-l2key=Gauche]').val(JSON.stringify(GaucheLatLng));
PolylineGauche.setCoordinates([[[CentreLatLng.lng,CentreLatLng.lat], [GaucheLatLng.lng,GaucheLatLng.lat]]]);
PolylineGauche.transform('EPSG:4326', 'EPSG:3857');
},Gauche);
features.push(Gauche);
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: features
})
});
map.addLayer(vectorLayer);
map.getView().fit(vectorLayer.getSource().getExtent(), map.getSize());
}
function addCondition(_condition,_el) {
var tr = $('<tr class="ConditionGroup">')
.append($('<td>')
.append($('<input type="checkbox" class="expressionAttr" data-l1key="enable"/>')))
.append($('<td>')
.append($('<div class="input-group">')
.append($('<span class="input-group-btn">')
.append($('<a class="btn btn-default conditionAttr btn-sm" data-action="remove">')
.append($('<i class="fa fa-minus-circle">'))))
.append($('<input class="expressionAttr form-control input-sm cmdCondition" data-l1key="expression"/>'))
.append($('<span class="input-group-btn">')
.append($('<a class="btn btn-warning btn-sm listCmdCondition">')
.append($('<i class="fa fa-list-alt">'))))))
.append($('<td>')
.append($('<select class="expressionAttr form-control input-sm cmdCondition" data-l1key="TypeGestion" />')
.append($('<option value="all">')
.text('{{Position du soleil et Jour / Nuit}}'))
.append($('<option value="Helioptrope">')
.text('{{Position du soleil}}'))
.append($('<option value="DayNight">')
.text('{{Jour / Nuit}}'))
.append($('<option value="Day">')
.text('{{Jour}}'))
.append($('<option value="Night">')
.text('{{Nuit}}')))
.append($('<select class="expressionAttr form-control input-sm cmdCondition" data-l1key="saison" />')
.append($('<option value="all">')
.text('{{Toutes les saisons}}'))
.append($('<option value="été">')
.text('{{Eté}}'))
.append($('<option value="hiver">')
.text('{{Hivers}}')))
.append($('<select class="expressionAttr form-control input-sm cmdCondition" data-l1key="evaluation" />')
.append($('<option value="all">')
.text('{{Ouverture et Fermeture}}'))
.append($('<option value="close">')
.text('{{Fermeture}}'))
.append($('<option value="open">')
.text('{{Ouverture}}')))
.append($('<select class="expressionAttr form-control input-sm cmdCondition" data-l1key="controle" />')
.append($('<option value="No">')
.text('{{Condition normale}}'))
.append($('<option value="Yes">')
.text('{{Condition vérifiée à l\'inverse si soleil dans fenêtre. Permet d\'ouvrir le volet l\'été et le fermer l\'hiver}}'))))
.append($('<td>'));
_el.append(tr);
_el.find('tr:last').setValues(_condition, '.expressionAttr');
}
function addAction(_action, _el) {
var tr = $('<tr class="ActionGroup">')
.append($('<td>')
.append($('<input type="checkbox" class="expressionAttr" data-l1key="enable"/>')))
.append($('<td>')
.append($('<div class="input-group">')
.append($('<span class="input-group-btn">')
.append($('<a class="btn btn-default ActionAttr btn-sm" data-action="remove">')
.append($('<i class="fa fa-minus-circle">'))))
.append($('<input class="expressionAttr form-control input-sm cmdAction" data-l1key="cmd"/>'))
.append($('<span class="input-group-btn">')
.append($('<a class="btn btn-success btn-sm listAction" title="Sélectionner un mot-clé">')
.append($('<i class="fa fa-tasks">')))
.append($('<a class="btn btn-success btn-sm listCmdAction">')
.append($('<i class="fa fa-list-alt">'))))))
.append($('<td>')
.append($(jeedom.cmd.displayActionOption(init(_action.cmd, ''), _action.options))));
_el.append(tr);
_el.find('tr:last').setValues(_action, '.expressionAttr');
}
$('#tab_zones a').click(function(e) {
e.preventDefault();
$(this).tab('show');
});
$('body').on('focusout','.expressionAttr[data-l1key=cmd]', function (event) {
var expression = $(this).closest('.ActionGroup').getValues('.expressionAttr');
var el = $(this);
jeedom.cmd.displayActionOption($(this).value(), init(expression[0].options), function (html) {
el.closest('.ActionGroup').find('.actionOptions').html(html);
})
});
$('body').on('click','.conditionAttr[data-action=add]',function(){
addCondition({},$(this).closest('.tab-pane').find('table'));
});
$('body').on('click','.conditionAttr[data-action=remove]',function(){
$(this).closest('tr').remove();
});
$('body').on('click','.listCmdCondition',function(){
var el = $(this).closest('tr').find('.expressionAttr[data-l1key=expression]');
jeedom.cmd.getSelectModal({cmd: {type: 'info'}}, function (result) {
var message = 'Aucun choix possible';
if(result.cmd.subType == 'numeric'){
message = '<div class="row"> ' +
'<div class="col-md-12"> ' +
'<form class="form-horizontal" onsubmit="return false;"> ' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >'+result.human+' {{est}}</label>' +
' <div class="col-xs-3">' +
' <select class="conditionAttr form-control" data-l1key="operator">' +
' <option value="==">{{égal}}</option>' +
' <option value=">">{{supérieur}}</option>' +
' <option value="<">{{inférieur}}</option>' +
' <option value="!=">{{différent}}</option>' +
' </select>' +
' </div>' +
' <div class="col-xs-4">' +
' <input type="number" class="conditionAttr form-control" data-l1key="operande" />' +
' </div>' +
'</div>' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >{{Ensuite}}</label>' +
' <div class="col-xs-3">' +
' <select class="conditionAttr form-control" data-l1key="next">' +
' <option value="">rien</option>' +
' <option value="OU">{{ou}}</option>' +
' </select>' +
' </div>' +
'</div>' +
'</div> </div>' +
'</form> </div> </div>';
}
if(result.cmd.subType == 'string'){
message = '<div class="row"> ' +
'<div class="col-md-12"> ' +
'<form class="form-horizontal" onsubmit="return false;"> ' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >'+result.human+' {{est}}</label>' +
' <div class="col-xs-3">' +
' <select class="conditionAttr form-control" data-l1key="operator">' +
' <option value="==">{{égale}}</option>' +
' <option value="matches">{{contient}}</option>' +
' <option value="!=">{{différent}}</option>' +
' </select>' +
' </div>' +
' <div class="col-xs-4">' +
' <input class="conditionAttr form-control" data-l1key="operande" />' +
' </div>' +
'</div>' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >{{Ensuite}}</label>' +
' <div class="col-xs-3">' +
' <select class="conditionAttr form-control" data-l1key="next">' +
' <option value="">{{rien}}</option>' +
' <option value="OU">{{ou}}</option>' +
' </select>' +
' </div>' +
'</div>' +
'</div> </div>' +
'</form> </div> </div>';
}
if(result.cmd.subType == 'binary'){
message = '<div class="row"> ' +
'<div class="col-md-12"> ' +
'<form class="form-horizontal" onsubmit="return false;"> ' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >'+result.human+' {{est}}</label>' +
' <div class="col-xs-7">' +
' <input class="conditionAttr" data-l1key="operator" value="==" style="display : none;" />' +
' <select class="conditionAttr form-control" data-l1key="operande">' +
' <option value="1">{{Ouvert}}</option>' +
' <option value="0">{{Fermé}}</option>' +
' <option value="1">{{Allumé}}</option>' +
' <option value="0">{{Éteint}}</option>' +
' <option value="1">{{Déclenché}}</option>' +
' <option value="0">{{Au repos}}</option>' +
' </select>' +
' </div>' +
' </div>' +
'<div class="form-group"> ' +
'<label class="col-xs-5 control-label" >{{Ensuite}}</label>' +
' <div class="col-xs-3">' +
' <select class="conditionAttr form-control" data-l1key="next">' +
' <option value="">{{rien}}</option>' +
' <option value="OU">{{ou}}</option>' +
' </select>' +
' </div>' +
'</div>' +
'</div> </div>' +
'</form> </div> </div>';
}
bootbox.dialog({
title: "{{Ajout d'une nouvelle condition}}",
message: message,
buttons: {
"Ne rien mettre": {
className: "btn-default",
callback: function () {
el.atCaret('insert', result.human);
}
},
success: {
label: "Valider",
className: "btn-primary",
callback: function () {
var condition = result.human;
condition += ' ' + $('.conditionAttr[data-l1key=operator]').value();
if(result.cmd.subType == 'string'){
if($('.conditionAttr[data-l1key=operator]').value() == 'matches'){
condition += ' "/' + $('.conditionAttr[data-l1key=operande]').value()+'/"';
}else{
condition += ' "' + $('.conditionAttr[data-l1key=operande]').value()+'"';
}
}else{
condition += ' ' + $('.conditionAttr[data-l1key=operande]').value();
}
condition += ' ' + $('.conditionAttr[data-l1key=next]').value()+' ';
el.atCaret('insert', condition);
if($('.conditionAttr[data-l1key=next]').value() != ''){
el.click();
}
}
},
}
});
});
});
$('body').on('click','.ActionAttr[data-action=add]',function(){
addAction({},$(this).closest('.tab-pane').find('table'));
});
$('body').on('click','.ActionAttr[data-action=remove]', function () {
$(this).closest('.ActionGroup').remove();
});
$("body").on('click', ".listAction", function() {
var el = $(this).closest('td').find('.expressionAttr[data-l1key=cmd]');
jeedom.getSelectActionModal({}, function (result) {
el.value(result.human);
jeedom.cmd.displayActionOption(el.value(), '', function (html) {
el.closest('.form-group').find('.actionOptions').html(html);
});
});
});
$("body").on('click', ".listCmdAction", function() {
var el = $(this).closest('td').find('.expressionAttr[data-l1key=cmd]');
jeedom.cmd.getSelectModal({cmd: {type: 'action'}}, function (result) {
el.value(result.human);
jeedom.cmd.displayActionOption(el.value(), '', function (html) {
el.closest('.form-group').find('.actionOptions').html(html);
});
});
});
function addCmdToTable(_cmd) {
var tr =$('<tr class="cmd" data-cmd_id="' + init(_cmd.id) + '">');
tr.append($('<td>')
.append($('<input type="hidden" class="cmdAttr form-control input-sm" data-l1key="id">'))
.append($('<input class="cmdAttr form-control input-sm" data-l1key="name" value="' + init(_cmd.name) + '" placeholder="{{Name}}" title="Name">')));
var parmetre=$('<td>');
parmetre.append($('<span class="type" type="' + init(_cmd.type) + '">')
.append(jeedom.cmd.availableType()));
parmetre.append($('<span class="subType" subType="'+init(_cmd.subType)+'">'));
if (is_numeric(_cmd.id)) {
parmetre.append($('<a class="btn btn-default btn-xs cmdAction" data-action="test">')
.append($('<i class="fa fa-rss">')
.text('{{Tester}}')));
}
parmetre.append($('<a class="btn btn-default btn-xs cmdAction tooltips" data-action="configure">')
.append($('<i class="fa fa-cogs">')));
parmetre.append($('<div>')
.append($('<span>')
.append($('<label class="checkbox-inline">')
.append($('<input type="checkbox" class="cmdAttr checkbox-inline" data-size="mini" data-label-text="{{Historiser}}" data-l1key="isHistorized" checked/>'))
.append('{{Historiser}}')
.append($('<sup>')
.append($('<i class="fa fa-question-circle tooltips" style="font-size : 1em;color:grey;">')
.attr('title','Souhaitez vous Historiser les changements de valeur'))))));
parmetre.append($('<div>')
.append($('<span>')
.append($('<label class="checkbox-inline">')
.append($('<input type="checkbox" class="cmdAttr checkbox-inline" data-size="mini" data-label-text="{{Afficher}}" data-l1key="isVisible" checked/>'))
.append('{{Afficher}}')
.append($('<sup>')
.append($('<i class="fa fa-question-circle tooltips" style="font-size : 1em;color:grey;">')
.attr('title','Souhaitez vous afficher cette commande sur le dashboard'))))));
tr.append(parmetre);
$('#table_cmd tbody').append(tr);
$('#table_cmd tbody tr:last').setValues(_cmd, '.cmdAttr');
jeedom.cmd.changeType($('#table_cmd tbody tr:last'), init(_cmd.subType));
}
et Volets/core/class/Volets.class.php
Code : Tout sélectionner
<?php
require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php';
class Volets extends eqLogic {
public static function deamon_info() {
$return = array();
$return['log'] = 'Volets';
$return['launchable'] = 'ok';
$return['state'] = 'nok';
foreach(eqLogic::byType('Volets') as $Volet){
if($Volet->getIsEnable()){
$listener = listener::byClassAndFunction('Volets', 'pull', array('Volets_id' => $Volet->getId()));
if (!is_object($listener))
return $return;
if ($Volet->getConfiguration('DayNight')){
$cron = cron::byClassAndFunction('Volets', 'ActionJour', array('Volets_id' => $Volet->getId()));
if (!is_object($cron))
return $return;
$cron = cron::byClassAndFunction('Volets', 'ActionNuit', array('Volets_id' => $Volet->getId()));
if (!is_object($cron))
return $return;
}
}
}
$return['state'] = 'ok';
return $return;
}
public static function deamon_start($_debug = false) {
log::remove('Volets');
self::deamon_stop();
$deamon_info = self::deamon_info();
if ($deamon_info['launchable'] != 'ok')
return;
if ($deamon_info['state'] == 'ok')
return;
foreach(eqLogic::byType('Volets') as $Volet)
$Volet->StartDemon();
}
public static function deamon_stop() {
foreach(eqLogic::byType('Volets') as $Volet){
$listener = listener::byClassAndFunction('Volets', 'pull', array('Volets_id' => $Volet->getId()));
if (is_object($listener))
$listener->remove();
$cron = cron::byClassAndFunction('Volets', 'ActionJour', array('Volets_id' => $Volet->getId()));
if (is_object($cron))
$cron->remove();
$cron = cron::byClassAndFunction('Volets', 'ActionNuit', array('Volets_id' => $Volet->getId()));
if (is_object($cron))
$cron->remove();
}
}
public static function pull($_option) {
log::add('Volets', 'debug', 'Objet mis à jour => ' . json_encode($_option));
$Volet = Volets::byId($_option['Volets_id']);
if (is_object($Volet) && $Volet->getIsEnable()) {
$Event = cmd::byId($_option['event_id']);
if(is_object($Event)){
switch($Event->getlogicalId()){
case 'azimuth360':
log::add('Volets', 'info',$Volet->getHumanName().' : Gestion des volets par l\'azimuth');
$Volet->ActionAzimute($_option['value']);
break;
case 'sunrise':
log::add('Volets', 'info',$Volet->getHumanName().' : Replanification de l\'ouverture au lever du soleil');
$timstamp=$Volet->CalculHeureEvent($_option['value'],'DelaisDay');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $Volet->CreateCron($Schedule, 'ActionJour');
break;
case 'sunset':
log::add('Volets', 'info',$Volet->getHumanName().' : Replanification de la fermeture au coucher du soleil');
$timstamp=$Volet->CalculHeureEvent($_option['value'],'DelaisNight');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $Volet->CreateCron($Schedule, 'ActionNuit');
break;
}
}
}
}
public static function ActionJour($_option) {
log::add('Volets', 'debug', 'Objet mis à jour => ' . json_encode($_option));
$Volet = Volets::byId($_option['Volets_id']);
if (is_object($Volet) && $Volet->getIsEnable()) {
log::add('Volets', 'info', $Volet->getHumanName().' : Exécution de la gestion du lever du soleil');
$Saison=$Volet->getSaison();
$result=$Volet->EvaluateCondition('open',$Saison,'Day','No');
if($result){
$Action=$Volet->getConfiguration('action');
$Volet->ExecuteAction($Action['open']);
cache::set('Volets::Position::'.$Volet->getId(), 'open', 0);
}else{
log::add('Volets', 'info',$Volet->getHumanName().' : Replanification de l\'évaluation des conditions d\'ouverture au lever du soleil');
$timstamp=$Volet->CalculHeureEvent(date('Hi'),'DelaisEval');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $Volet->CreateCron($Schedule, 'ActionJour', array('Volets_id' => intval($Volet->getId())));
}
}
}
public static function ActionNuit($_option) {
log::add('Volets', 'debug', 'Objet mis à jour => ' . json_encode($_option));
$Volet = Volets::byId($_option['Volets_id']);
if (is_object($Volet) && $Volet->getIsEnable()) {
log::add('Volets', 'info',$Volet->getHumanName().' : Exécution de la gestion du coucher du soleil ');
$Saison=$Volet->getSaison();
$result=$Volet->EvaluateCondition('close',$Saison,'Night','No');
if($result){
$Action=$Volet->getConfiguration('action');
$Volet->ExecuteAction($Action['close']);
cache::set('Volets::Position::'.$Volet->getId(), 'close', 0);
}else{
log::add('Volets', 'info', $Volet->getHumanName().' : Replanification de l\'évaluation des conditions de fermeture au coucher du soleil');
$timstamp=$Volet->CalculHeureEvent(date('Hi'),'DelaisEval');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $Volet->CreateCron($Schedule, 'ActionNuit', array('Volets_id' => intval($Volet->getId())));
}
}
}
public function ActionAzimute($Azimuth) {
if($this->getCmd(null,'isArmed')->execCmd()){
if($this->checkJour()){
$Saison=$this->getSaison();
$Evenement=$this->SelectAction($Azimuth,$Saison);
if($Evenement != false){
$conditon=$this->EvaluateCondition($Evenement,$Saison,'Helioptrope','No');
/*if(!$conditon && $Evenement =='open')
$Evenement =='close';
if(!$conditon && $Evenement =='close')
$Evenement =='open';*/
$position = cache::byKey('Volets::Position::'.$this->getId());
if(!$conditon) {
log::add('Volets','info',$this->getHumanName().' : Je teste les conditions inversées');
$conditon=$this->EvaluateCondition($Evenement,$Saison,'Helioptrope','Yes');
if($conditon) {
$Action=$this->getConfiguration('action');
if($position->getValue('') == $Evenement and $Evenement == 'close' and $Saison == 'été'){
log::add('Volets','info',$this->getHumanName().' : Position actuelle est '.$Evenement.' conditions inversées validées, j ouvre les volets');
$this->ExecuteAction($Action['open']);
cache::set('Volets::Position::'.$this->getId(), 'open', 0);
}
if($position->getValue('') == $Evenement and $Evenement == 'open' and $Saison == 'hivers'){
log::add('Volets','info',$this->getHumanName().' : Position actuelle est '.$Evenement.' conditions inversées validées, je ferme les volets');
$this->ExecuteAction($Action['close']);
cache::set('Volets::Position::'.$this->getId(), 'close', 0);
}
}
return;
}
$Action=$this->getConfiguration('action');
$position = cache::byKey('Volets::Position::'.$this->getId());
if($position->getValue('') != $Evenement){
log::add('Volets','info',$this->getHumanName().' : Position actuelle est '.$Evenement);
$this->ExecuteAction($Action[$Evenement]);
cache::set('Volets::Position::'.$this->getId(), $Evenement, 0);
}
else {
log::add('Volets','info',$this->getHumanName().' : Position actuelle est '.$Evenement.' les volets sont déjà dans la bonne position, je ne fait rien');
}
}
return;
}
log::add('Volets','debug',$this->getHumanName().' : Il fait nuit, la gestion par azimuth est désactivée');
}
else
log::add('Volets','debug',$this->getHumanName().' : Gestion par azimuth désactivée');
}
public function checkJour() {
$heliotrope=eqlogic::byId($this->getConfiguration('heliotrope'));
if(is_object($heliotrope)){
$sunrise=$heliotrope->getCmd(null,'sunrise');
if(is_object($sunrise)){
$value=$sunrise->execCmd();
$Jours= new DateTime('@' .$this->CalculHeureEvent($value,'DelaisDay'));
}
else{
log::add('Volets','debug',$this->getHumanName().' : L\'objet "sunrise" n\'a pas été trouvé');
return false;
}
$sunset=$heliotrope->getCmd(null,'sunset');
if(is_object($sunset)){
$value=$sunset->execCmd();
$Nuit= new DateTime('@' .$this->CalculHeureEvent($value,'DelaisNight'));
}else{
log::add('Volets','debug',$this->getHumanName().' : L\'objet "sunset" n\'a pas été trouvé');
return false;
}
$Now=new DateTime();
if($Now>$Jours && $Now<$Nuit)
return true;
}else
log::add('Volets','debug',$this->getHumanName().' : Aucune commande Héliotrope configurée');
return false;
}
public function CheckAngle($Azimuth) {
$Droite=$this->getConfiguration('Droite');
$Gauche=$this->getConfiguration('Gauche');
$Centre=$this->getConfiguration('Centre');
if(is_array($Droite)&&is_array($Centre)&&is_array($Gauche)){
$AngleCntDrt=$this->getAngle(
$Centre['lat'],
$Centre['lng'],
$Droite['lat'],
$Droite['lng']);
$AngleCntGau=$this->getAngle(
$Centre['lat'],
$Centre['lng'],
$Gauche['lat'],
$Gauche['lng']);
log::add('Volets','info',$this->getHumanName().' : La fenêtre d\'ensoleillement est comprise entre : '.$AngleCntDrt.'° et '.$AngleCntGau.'°');
if ($AngleCntDrt < $AngleCntGau){
if($AngleCntDrt <= $Azimuth && $Azimuth <= $AngleCntGau)
return true;
}else{
if($AngleCntDrt <= $Azimuth && $Azimuth <= 360)
return true;
if(0 <= $Azimut && $Azimuth <= $AngleCntGau)
return true;
}
}else
log::add('Volets','debug',$this->getHumanName().' : Les coordonnées GPS de l\'angle d\'exposition au soleil de votre fenêtre sont mal configurées');
return false;
}
public function getSaison() {
$isInWindows=$this->getCmd(null,'isInWindows');
if(!is_object($isInWindows))
return false;
if($isInWindows->execCmd()){
log::add('Volets','info',$this->getHumanName().' : Le plugin est configuré en mode hiver');
return 'hiver';
}else{
log::add('Volets','info',$this->getHumanName().' : Le plugin est configuré en mode été');
return 'été';
}
return false;
}
public function SelectAction($Azimuth,$saison) {
$Action=false;
$StateCmd=$this->getCmd(null,'state');
if(!is_object($StateCmd))
return false;
if($this->CheckAngle($Azimuth)){
$StateCmd->event(true);
log::add('Volets','info',$this->getHumanName().' : Le soleil est dans la fenêtre');
if($saison =='hiver')
$Action='open';
else
$Action='close';
}else{
$StateCmd->event(false);
log::add('Volets','info',$this->getHumanName().' : Le soleil n\'est pas dans la fenêtre');
if($saison == 'été')
$Action='open';
else
$Action='close';
}
$StateCmd->setCollectDate(date('Y-m-d H:i:s'));
$StateCmd->save();
return $Action;
}
public function ExecuteAction($Action) {
foreach($Action as $cmd){
if (isset($cmd['enable']) && $cmd['enable'] == 0)
continue;
try {
$options = array();
if (isset($cmd['options']))
$options = $cmd['options'];
scenarioExpression::createAndExec('action', $cmd['cmd'], $options);
} catch (Exception $e) {
log::add('Volets', 'error',$this->getHumanName().' : '. __('Erreur lors de l\'exécution de ', __FILE__) . $action['cmd'] . __('. Détails : ', __FILE__) . $e->getMessage());
}
$Commande=cmd::byId(str_replace('#','',$cmd['cmd']));
if(is_object($Commande)){
if($this->getConfiguration('isRandom'))
sleep(rand(0,$this->getConfiguration('DelaisPresence')));
log::add('Volets','debug',$this->getHumanName().' : Exécution de '.$Commande->getHumanName());
$Commande->event($cmd['options']);
}
}
}
public function CalculHeureEvent($HeureStart, $delais) {
if(strlen($HeureStart)==3)
$Heure=substr($HeureStart,0,1);
else
$Heure=substr($HeureStart,0,2);
$Minute=floatval(substr($HeureStart,-2));
if($this->getConfiguration($delais)!='')
$Minute+=floatval($this->getConfiguration($delais));
while($Minute>=60){
$Minute-=60;
$Heure+=1;
}
return mktime($Heure,$Minute);
}
public function CreateCron($Schedule, $logicalId) {
$cron =cron::byClassAndFunction('Volets', $logicalId, array('Volets_id' => $this->getId()));
if (!is_object($cron)) {
$cron = new cron();
$cron->setClass('Volets');
$cron->setFunction($logicalId);
$cron->setOption(array('Volets_id' => $this->getId()));
$cron->setEnable(1);
$cron->setDeamon(0);
$cron->setSchedule($Schedule);
$cron->save();
}else{
$cron->setSchedule($Schedule);
$cron->save();
}
return $cron;
}
public function EvaluateCondition($Evenement,$Saison,$TypeGestion,$Controle){
foreach($this->getConfiguration('condition') as $condition){
if($condition['evaluation']!=$Evenement && $condition['evaluation']!='all')
continue;
if($condition['saison']!=$Saison && $condition['saison']!='all')
continue;
if(stripos($condition['TypeGestion'],$TypeGestion) === false && $condition['TypeGestion']!='all')
continue;
if (isset($condition['enable']) && $condition['enable'] == 0)
continue;
$_scenario = null;
$expression = scenarioExpression::setTags($condition['expression'], $_scenario, true);
$message = __('Evaluation de la condition : [', __FILE__) . trim($expression) . '] = ';
$result = evaluate($expression);
if (is_bool($result)) {
if ($result) {
$message .= __('Vrai', __FILE__);
} else {
$message .= __('Faux', __FILE__);
}
} else {
$message .= $result;
}
if($Controle == 'Yes' and $condition['controle'] == 'Yes' and !$result) {
$result = true;
$message .= __(' inversé', __FILE__);
}
log::add('Volets','info',$this->getHumanName().' : '.$message);
if(!$result){
log::add('Volets','info',$this->getHumanName().' : Les conditions ne sont pas remplies');
return false;
}
}
log::add('Volets','info',$this->getHumanName().' : Les conditions sont remplies');
return true;
}
public function getAngle($latitudeOrigine,$longitudeOrigne, $latitudeDest,$longitudeDest) {
$rlongitudeOrigne = deg2rad($longitudeOrigne);
$rlatitudeOrigine = deg2rad($latitudeOrigine);
$rlongitudeDest = deg2rad($longitudeDest);
$rlatitudeDest = deg2rad($latitudeDest);
$longDelta = $rlongitudeDest - $rlongitudeOrigne;
$y = sin($longDelta) * cos($rlatitudeDest);
$x = (cos($rlatitudeOrigine)*sin($rlatitudeDest)) - (sin($rlatitudeOrigine)*cos($rlatitudeDest)*cos($longDelta));
$angle = rad2deg(atan2($y, $x));
if ($angle < 0) {
$angle += 360;
}
return floatval($angle % 360);
}
public function StartDemon() {
if($this->getIsEnable()){
$heliotrope=eqlogic::byId($this->getConfiguration('heliotrope'));
if(is_object($heliotrope)){
$sunrise=$heliotrope->getCmd(null,'sunrise');
if(!is_object($sunrise))
return false;
$sunset=$heliotrope->getCmd(null,'sunset');
if(!is_object($sunset))
return false;
$listener = listener::byClassAndFunction('Volets', 'pull', array('Volets_id' => $this->getId()));
if (!is_object($listener))
$listener = new listener();
$listener->setClass('Volets');
$listener->setFunction('pull');
$listener->setOption(array('Volets_id' => $this->getId()));
$listener->emptyEvent();
if ($this->getConfiguration('Helioptrope'))
$listener->addEvent($heliotrope->getCmd(null,'azimuth360')->getId());
if ($this->getConfiguration('DayNight')){
$listener->addEvent($sunrise->getId());
$listener->addEvent($sunset->getId());
$value=$sunrise->execCmd();
$timstamp=$this->CalculHeureEvent($value,'DelaisDay');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $this->CreateCron($Schedule, 'ActionJour', array('Volets_id' => intval($this->getId())));
$value=$sunset->execCmd();
$timstamp=$this->CalculHeureEvent($value,'DelaisNight');
$Schedule=date("i",$timstamp) . ' ' . date("H",$timstamp) . ' * * * *';
$cron = $this->CreateCron($Schedule, 'ActionNuit', array('Volets_id' => intval($this->getId())));
}
$listener->save();
}
}
}
public static function AddCommande($eqLogic,$Name,$_logicalId,$Type="info", $SubType='binary',$visible,$Template='') {
$Commande = $eqLogic->getCmd(null,$_logicalId);
if (!is_object($Commande))
{
$Commande = new VoletsCmd();
$Commande->setId(null);
$Commande->setName($Name);
$Commande->setIsVisible($visible);
$Commande->setLogicalId($_logicalId);
$Commande->setEqLogic_id($eqLogic->getId());
$Commande->setType($Type);
$Commande->setSubType($SubType);
}
$Commande->setTemplate('dashboard',$Template );
$Commande->setTemplate('mobile', $Template);
$Commande->save();
return $Commande;
}
public function postSave() {
$state=self::AddCommande($this,"Position du soleil","state","info", 'binary',true,'sunInWindows');
$state->event(false);
$state->setCollectDate(date('Y-m-d H:i:s'));
$state->save();
$isInWindows=self::AddCommande($this,"Etat mode","isInWindows","info","binary",false,'isInWindows');
$inWindows=self::AddCommande($this,"Mode","inWindows","action","other",true,'inWindows');
$inWindows->setValue($isInWindows->getId());
$inWindows->save();
$isArmed=self::AddCommande($this,"Etat activation","isArmed","info","binary",false,'lock');
$isArmed->event(true);
$isArmed->setCollectDate(date('Y-m-d H:i:s'));
$isArmed->save();
$Armed=self::AddCommande($this,"Activer","armed","action","other",true,'lock');
$Armed->setValue($isArmed->getId());
$Armed->setConfiguration('state', '1');
$Armed->setConfiguration('armed', '1');
$Armed->save();
$Released=self::AddCommande($this,"Désactiver","released","action","other",true,'lock');
$Released->setValue($isArmed->getId());
$Released->save();
$Released->setConfiguration('state', '0');
$Released->setConfiguration('armed', '1');
self::deamon_stop();
}
public function postRemove() {
$listener = listener::byClassAndFunction('Volets', 'pull', array('Volets_id' => $this->getId()));
if (is_object($listener))
$listener->remove();
$cron = cron::byClassAndFunction('Volets', 'ActionJour', array('Volets_id' => $this->getId()));
if (is_object($cron))
$cron->remove();
$cron = cron::byClassAndFunction('Volets', 'ActionNuit', array('Volets_id' => $this->getId()));
if (is_object($cron))
$cron->remove();
}
}
class VoletsCmd extends cmd {
public function execute($_options = null) {
$Listener=cmd::byId(str_replace('#','',$this->getValue()));
if (is_object($Listener)) {
switch($this->getLogicalId()){
case 'armed':
$Listener->event(true);
break;
case 'released':
$Listener->event(false);
break;
case 'inWindows':
if($Listener->execCmd())
$Listener->event(false);
else
$Listener->event(true);
break;
}
$Listener->setCollectDate(date('Y-m-d H:i:s'));
$Listener->save();
}
}
}
?>