Aller au contenu

La domotique HC2 chez J3R3M!


J3R3M

Recommended Posts

Bonjour à tous,

 

Dans ce fil, je vais vous expliquer et partager avec vous les principaux et différents éléments qui ont rendu mon appartement intelligent.

Je dis bien intelligent, car pour moi, c'est le but premier de la domotique. Allumer la lumière ou fermer les volets quand je suis en déplacement, c'est marrant, mais c'est pas ça qui me change la vie!

Mon installation est donc simple et constituée de peu de modules finalement. Dans chaque pièce, il y a au minimum un détecteur de mouvements (Caméra et/ou FGMS001) et un éclairage connecté.

J'utilise également Jeedom pour supporter des protocoles autres que Z-Wave, mais cela ne fait pas parti des éléments importants de la domotique.

 

Les explications seront agrémentées au fur-et-à-mesure.

Tout cela a été programmé il y a un moment, il faut moi-même que je retrouve mes petits :D

 

Les scènes importantes sont :

  • Check 1mn qui tourne toutes les minutes 24/24h pour faire des vérifications régulières
  • NetAtmo Welcome que j'ai personnalisé pour mes besoins (Scène originale postée ici)
  • Pièces 2019 qui sera actionnée dès une action dans une pièce. Cette même scène est capable de gérer chacun des pièces intérieures de l'appartement : Volets Roulants, Eclairages, Système d'enceintes...
  • Watchdog qui vérifie simplement que la scène Check 1mn s'exécute correctement et la redémarre le cas échéant.

 

Moins importantes mais néanmoins utiles :

 

1339498869_ScenesPrincipales.png.f81dda5a420573b5525e9ac8ed9beebf.png

 

Le VD important est Etat Pièces. C'est surtout sa Main loop qui est importante puisqu'elle gère la variation et extinction des lumières et enceintes en fonction des mouvements des pièces.

Je l'utilise en VD puisque je voulais avoir une visualisation sur ce qu'il se passait en le programmant. Cela a toujours bien fonctionné ainsi et je l'ai laissé sous cette forme.

Ce VD est également surveillé par l'indispensable scène Watchdog. J'expliquerai son fonctionnement de manière plus précise par la suite.

 

1509500179_Etatpieces.png.5746324b45dc6928e89407c4a971982a.png

 

Quelques autres VD (sans Mainloop sauf Surveillance Station) me servent uniquement pour avoir une visualisation de l'état actuel de certaines Variables Globales.

Les scènes agissent majoritairement sur les boutons de ces VD pour changer l'état de la variable globale correspondante.

 

VG.png.df0baed75a04b601d428139acfa1b8c9.png

 

D'autres me servent à avoir une interface d'administration sans avoir à programmer quelque chose pour modifier le comportement des scènes.

Également, j'expliquerai par la suite la fonction de chaque VD si cela peut intéresser certaines personnes.

 

Administration.png.e702af904ddb83516c3edc18c627fee5.png

 

Avant toutes chose, il faut savoir que toutes les scènes et tous les VDs utilisent des informations encodées en JSON dans une variable globale qui s'appelle T_INFOS_PIECES dont voici l'architecture et un exemple

  • id ID de la pièce correspond à l'id du bouton du VD Pièce Active
  • Code  Code de la pièce. Doit être similaire à la clé du tableau principal
  • Nom Nom de la pièce avec majuscule et accents (pour utilisation propre dans SMS par ex)
  • Article Article du nom de la pièce (ex : "l'" pour "entrée")
  • Detect Table des id des détecteurs Fibaro. Si cam, mettre "cam"
  • LumMini À partir de quel seuil de luminosité (lux) la lumière doit-elle s'allumer. nil si uniquement cam
  • LumMax Table des luminosités maximales détectées par chaque détecteur lorsque toutes les lampes gérées sont allumées à 100%. Le but étant de se baser sur ses valeurs pour déterminer si une autre source de lumière est présente.
  • Passage 0/1 - Pièce de passage ou non ? Par exemple, un couloir est un lieu de passage.
  • TpsActive Temps maxi durant lequel la pièce restera considérée comme active sans le moindre mouvement
  • TpsMise Temps maxi durant lequel la mise resetera active sans le moindre mouvement
  • JourNuit 0/1 - Gestion automatique de l'allumage de la pièce (basé sur les heures de levés et couchés du soleil). Utile lorsque seule une cam détecte les mouvements de la pièce
  • HueGroup Table des Ids des VDs Groupe Hue de la pièce
  • HuePreset Bouton du VD à appuyer pour un preset de couleur standard. Ces boutons sont actionnés à la désactivation de HOME_DODO par exemple.
  • HueList Table des Ids des VDs des ampoules Hues utilisées dans la pièce
  • HueType Table des types des lampes Hues précédemment déclarées
  • HuePowerDodo Table des valeurs lorsque la pièce est en mode DODO
  • HuePowerAM Table des valeurs lorsque Moment = Matinée
  • HuePowerMidi Table des valeurs lorsque Moment = Midi
  • HuePowerPM Table des valeurs lorsque Moment = Après-Midi
  • HuePowerSoir Table des valeurs lorsque Moment = Soirée
  • HuePowerNuit Table des valeurs lorsque Moment = Nuit
  • SonosId Table des ID des VD SONOS de la pièce
  • SonosVMax Table contenant les volumes maxi autorisés pour les enceintes de la pièce, en fonction du moment de la journée
  • SonosV Table contenant les volumes auxquels seront montées les SONOS en fonction du moment de la journée
  • SonosFadeOut ID de la scène spécifique qui fait le FADE OUT de la pièce
  • VoletsR IDs des Roller Shutter de la pièce
  • Chambre La pièce est-elle une chambre ?
  • Netatmo Uniquement si Chambre = 1. Tableau contenant les noms (Netatmo) des personnes dormant dans cette chambre. Les personnes seront donc déclarées absentes lorsqu'elles seront couchées, si elles ont été vues dans l'heure précédent le coucher.
local pieces = {};

pieces["ENTREE"] = {
id = 1,
Code = "ENTREE",
Nom = "Entrée",
Article = "l'",
Detect = {"cam"},
LumMini = nil,
LumMax = {nil},
Passage = 1,
TpsActive = 2,
TpsMise = 120,
JourNuit = 0,
HueGroup = {298},
HuePreset = {Sat=20, Bri=90, Color=10000},
HueList = {89,96,113,112}, -- 112 = Couloir
HueType = {"hcol", "hcol", "hcol", "hcol"},
HuePowerDodo = {5,0,0,5},
HuePowerAM = {30,30,30,45},
HuePowerMidi = {40,40,40,50},
HuePowerPM = {40,40,40,50},
HuePowerSoir = {40,40,40,50},
HuePowerNuit = {30,30,30,40},
SonosId = {245},
SonosVMax = {AM=40,Midi=50,PM=50,Soir=50,Nuit=40},
SonosV = {AM=30,Midi=35,PM=35,Soir=35,Nuit=30},
SonosFadeOut = 186,
VoletsR = {nil},
Chambre = 0
};

 

Modifié par J3R3M
  • Like 1
  • Upvote 1
Lien vers le commentaire
Partager sur d’autres sites

Check 1mn

Cette scène est exécutée toutes les minutes 24/24h dans le but de faire des vérifications constantes et mettre à jour les variables qui le nécessitent.

 

Fonction InfosPieces

  • Parcourt le JSON stocké dans T_INFOS_PIECES pour y récupérer les éléments nécessaires
  • Récupération des IDs des détecteusr de mouvements des FGMS001 pour en déduire celui de la température (ID+1)
  • Comparaison des valeurs récupérées avec les valeurs mini et maxi paramétrées dans T_TEMPERATURES. Si hors champ -> Envoi SMS
  • Si une mise est active mais qu'aucun mouvement n'a été détecté dans la pièce en question depuis plus du temps indiqué dans la clé Mise de la pièce (T_INFOS_PIECES)  -> Désactivation

Une mise est un état lumineux enregistré qui ne sera pas impacté par la domotique pendant un laps de temps prédéfini.

  • Vérification si les lumières de la pièce traitée sont allumées. Si elles le sont sans raison, elles sont éteintes.

Pour vérifier si une lumière est allumée à juste titre, je vérifie la valeur de la mise (NomPiece_Mise) et la valeur de l'état (NomPiece_Etat)

    • Etat=0 : Pièce inactive
    • Etat=1 : Pièce considérée comme inactive dans les prochaines 10 secondes (Si lumière allumée, elle sera tamisée)
    • Etat=3 : Pièce considéré comme active (Si lumière nécessaire, elle aura été allumée par la scène Pièces)
  • Gestion du mode nuit : HOME_DODO
    • Les chambres sont comptées
    • Si toutes les chambres sont en mode DODO (VG DODO_NomPiece) :
      • Le minimum entre deux modes DODO consécutifs est fixé sur 4h
      • Si la scène calcule que le mode DODO souhaiterait se ré-enclencher aussitôt après les 4h, plusieurs alertes lumineuses seront faites successivement
      • Ces signaux sont destinés à avertir de ce mode qui va s'enclencher et permet à chacun de désactiver le mode DODO si ça avait été un oubli

Pourquoi? Car une seule personne provenant d'une même chambre peut être levée. Dans ce cas, le mode DODO sera désactivé (HOME_DODO = 0) alors que la chambre le sera toujours (DODO_NomPiece = 1). Si la seconde personne se lève sans désactiver ce mode DODO de la chambre, il est possible que ce mode DODO se réactive inopinément dans les heures suivantes si aucune alerte lumineuse n'était effectuée.

  • La fonction retourne une valeur booléenne. True si HOME_DODO=1 & False si HOME_DODO = 0.

 

Fonction Check

  • Modes Absence (VG Absence) :
    • Mode 1
      • Extinction de toutes les lumières
      • Extinction de toutes les enceintes
      • Désactivation de toutes les mises
      • On indique les absences de tout le monde dans l'API NetAtmo
      • Activation des caméras
      • Notification du mode par SMS
      • Si la prise TV consomme moins de 50W, on l'éteint (sinon, c'est que quelqu'un la regarde)
    • Mode 2
      • Actions du Mode 1 +
      • Valeur de la VG Absence affectée sur "ok"
      • Extinction de la TV
  • Si aucun mouvement depuis plus de 3h et que le mode DODO est désactivé, on active le mode Absence Niveau 2
  • Si un enregistrement des caméras est en cours et qu'aucun mouvement n'est détecté depuis plus de 2mn, on désactive l'enregistrement
  • On rentre et on sort dans l'appartement par la pièce ENTREE, qui a été précisée comme un lieu uniquement de passage dans T_INFOS_PIECES. Par conséquent, si PIECE_ACTIVE contient ENTREE après 2mn sans mouvement, c'est que quelqu'un est sorti de l'appartement.
    • Comme pour n'importe quelle pièce, l'éclairage se tamise avant d'être éteint
    • Si au moins une chambre est encore en mode DODO, activation du mode Absence Niveau 1
    • Si aucune chambre n'est en mode DODO :
      • Extinction de la lumière si la TV est allumée
      • Activation du mode Absence Niveau 2 si la TV n'est pas allumée

 

Fonction Time

  • Execution des fonctions InfosPieces et Check
  • Maintien à jour de Moment de la Journée
  • Maintin à jour de Saison
  • Si la consommation relevée du réfrigérateur est inférieure à celle indiquée dans Seuil_Alerte_Elec -> Notification SMS
  • Si des lumières sont allumées alors que le mode Absence est enclenché -> Démarrage de la scène éteignant tous les devices lumières
  • Si une valeur est définie dans Tests SMS, envoi du SMS à l'heure paramétrée

 

MODIFS À FAIRE :

- Mode Absence directement géré par la fonction Action

- Changer le nom de cette fonction Action!

--[[
%% autostart
--]]

-- Variables Refresh
local delai = 1
local DELAI = delai * 60;

-- Variable Netatmo
local NETATMO_HomeId = "";

-- Fonction HTTP
local http = net.HTTPClient();

-- On récupère les infos de temps
local minuteries = json.decode(fibaro:getGlobalValue("HOME_MINUTERIES"));

-- Debug
local debug = 1;
local function Debug(color,message)
  color = color or "white";
  if debug == 1 and message ~= nil then
    fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
  end
end

-- Envoi SMS
local function envoi_sms(sms)
  if os.time() - fibaro:getGlobalModificationTime("DERNIER_SMS") > 20*60 then
    local char_to_hex = function(c) return string.format("%%%02X", string.byte(c)) end
    local function urlencode(url)
      if url == nil then return end
      url = url:gsub("\n", "\r\n")
      url = url:gsub("([^%w ])", char_to_hex)
      url = url:gsub(" ", "+")
      url = url:gsub(">", "%0A")
      return url
    end
  local url = "http://192.168.2.14:9090/send.html?smsto=+33*********&smstype=sms&smsbody="..urlencode(sms);
  http:request(url, { options = { method = 'GET', data = json.encode(newVar)}});
  fibaro:setGlobal("DERNIER_SMS", os.time());
  else
    Debug("grey", "Un message n'a pas été envoyé en raison du temps défini entre les SMS.");
  end
end

-- Fonction explorant les valeurs de T_INFOS_PIECES
-- Contrôle température
-- Contrôle Mises
-- Contrôle si lumières allumées le sont à juste titre
-- Gestion Mode DODO -- Return valeur DODO par la fonction
local function InfosPieces()
  local table = json.decode(fibaro:getGlobalValue("T_INFOS_PIECES"));
  local InfosTemperatures = json.decode(fibaro:getGlobalValue("T_TEMPERATURES"));
  local NbChambres,NbDodo,Huegroup,boolean = 0,0,{},false;

  for k,v in pairs(table) do
    -- Début Contrôle températures
    local Devices = table[k].Detect;
    for i=1,#Devices do
      -- Si le détecteur traité est un FGMS001
      if type(Devices[i]) == "number" then
        local val = tonumber(fibaro:getValue(Devices[i]+1, "value"));
        -- Si la température est inférieure à ce qui a été paramétré
        if val < InfosTemperatures.mini then
          envoi_sms("[Domotique Info] La température de "..v.Article..v.Nom.." est inférieure à "..InfosTemperatures.mini.." °C.");
          Debug("yellow", "["..k.."] La température de la pièce est inférieure à "..InfosTemperatures.mini.." °C !");
        elseif val > InfosTemperatures.maxi then
          envoi_sms("[Domotique Info] La température de "..v.Article..v.Nom.." est supérieure à "..InfosTemperatures.maxi.." °C.");
          Debug("yellow", "["..k.."] La température de la pièce est supérieure à "..InfosTemperatures.maxi.." °C !");
        end -- Conditions valeur température
      end -- Device est un nombre
    end -- Boucle
    -- Fin Contrôle températures

    -- Début - Vérification Mises
    local MisePiece = tonumber(fibaro:getGlobalValue(k.."_Mise"));
    local DeltaLastMove = math.floor((os.time() - tonumber(fibaro:getGlobalValue(k.."_LastMove")))/60);
    if MisePiece == 1 and DeltaLastMove > k.TpsMise then
      fibaro:setGlobal(k.."_Mise", 0);
      Debug("orange", "["..k.."] Mise automatiquement désactivée car aucun mouvement dans la pièce depuis plus de "..k.TpsMise.." mn.");
    end
    -- Fin -- Vérification Mises

    -- Début - Vérification des lumières
    local EtatPiece = tonumber(fibaro:getGlobalValue(k.."_Etat"));
    local HueGroup = table[k].HueGroup;
    for i=1,#HueGroup do
      local etat = fibaro:getValue(HueGroup[i], "ui.labelEtat.value");
      if ( MisePiece ~= 1 and EtatPiece < 1 and etat == "On" ) then
        fibaro:call(HueGroup[i], "pressButton", "44");
        Debug("blue", "["..k.."] [Groupe Hue "..HueGroup[i].."] Les lampes du groupe ont été éteintes.");
      end
    end
    -- Fin - Vérification des lumières

    -- Début Gestion DODO
    if table[k].Chambre == 1 then
      NbChambres = NbChambres+1;
      if fibaro:getGlobalValue("DODO_"..table[k].Code) == "1" then NbDodo = NbDodo+1; boolean = true;end
    end -- Fin Gestion DODO

  end -- Fin Boucle INFOS_PIECES
  -- Si toutes les chambres ont dodo=1, on active le mode nuit
  if NbChambres == NbDodo and fibaro:getGlobalValue("HOME_DODO") == "0" and fibaro:getGlobalValue("Absence") ~= "ok" and (os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"))) > 4*60*60 then
    -- Avertissement
    if (os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"))) == (4*60*60 + 1) then
      fibaro:call(302, "pressButton", 21); fibaro:call(302, "setSlider", "10", "30");
      Debug("yellow", "[DODO] Avertissement 1 avant activation");
    elseif (os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"))) == (4*60*60 + 2) then
      fibaro:call(302, "setSlider", "10", "40");
      Debug("yellow", "[DODO] Avertissement 2 avant activation");
    elseif (os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"))) == (4*60*60 + 4) then
      fibaro:call(302, "setSlider", "10", "100");
      Debug("yellow", "[DODO] Avertissement 3 avant activation");
    elseif (os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"))) > (4*60*60 + 5) then
      fibaro:call(162, "pressButton",1);
      Debug("blue", "[DODO] Activation du mode nuit");
    end
  end
  return boolean;
end

-- Vérifications si aucun mouvement
local function check(dodo)
  local function action(lvl)
    if lvl == 2 then
      if not dodo then fibaro:setGlobal("Absence", "ok"); end -- Modif Intrusion
      fibaro:call(217, "turnOff"); -- TV OFF
    else
      if tonumber(fibaro:getValue(217,"power")) < 50 then fibaro:call(217, "turnOff"); end -- Prise Multimédia
    end
    fibaro:startScene(69); -- Lumière OFF
    fibaro:startScene(94); -- SONOS OFF
    fibaro:startScene(66); -- Mises OFF
    fibaro:startScene(148);  -- Tout le monde absent API NetAtmo
    fibaro:startScene(127); -- Scène NetAtmo
    fibaro:call(155, "pressButton", 3); -- Activation Cams
    envoi_sms("[Domotique Info] Mode absence déclenché (Niv. "..lvl..")");
    fibaro:call(334, 'sendPush', "Mode absence déclenché (Niv. "..lvl..")")
    Debug("grey","-- Mode Absence (Niveau "..lvl..") --");
  end -- Fin Fonction

  local ilya = math.floor((os.time() - tonumber(fibaro:getGlobalModificationTime("DernierMouvement")))/60);

  if ilya >= 180 and not dodo and fibaro:getGlobalValue("Absence") ~= "ok" then action(2); end
  
  -- Arrêt enregistrement
  if ilya >= 2 and fibaro:getGlobalValue("SurvStation_Status") == "Recording" then
    fibaro:call(155, "pressButton", 2); Debug("red","[INFO] Enregistrement des caméras suspendu.");
  end
  -- Mode absence ?
  if fibaro:getGlobalValue("PIECE_ACTIVE") == "ENTREE" and fibaro:getGlobalValue("Absence") ~= "ok" then
    local VD = 298; -- ID VD Groupe Entrée
    if ilya == 2 then -- On tamise
      local Val = tonumber(fibaro:getValue(VD, "ui.Luminosite.value"));
      fibaro:call(VD, "setSlider", "10", math.floor(Val/2));
      fibaro:setGlobal("ENTREE_HueFade", 1);
    elseif ilya == 3 and dodo then -- Une chambre au moins est en mode DODO
      action(1); -- Sans activer Scène Intrusion
    elseif ilya == 3 and not dodo then -- Tout le monde est levé
      if tonumber(fibaro:getValue(217,"power")) < 50 then -- Personne ne regarde la TV
        action(2); -- Scène Intrusion démarée au prochain mouvement
      else
        fibaro:call(VD, "pressButton", "44"); -- Simplement Extinction de la lumière
      end
    end
  end -- Etat Piece_active & Absence
end -- Fonction

-- Gestion Variable Moment de la journée
local function moment_journee(Heures,Minutes)
  -- Mise à jour de la variable Moments de la journée
  if ( Heures == 7 and Minutes == 0 ) then fibaro:call(174, "pressButton", "1");
  --fibaro:debug("Moment de la journée : Matinée");
  elseif ( Heures == 12 and Minutes == 0 ) then fibaro:call(174, "pressButton", "2");
  --fibaro:debug("Moment de la journée : Midi");
  elseif ( Heures == 13 and Minutes == 30 ) then fibaro:call(174, "pressButton", "3");
  --fibaro:debug("Moment de la journée : Après-Midi");
  elseif ( Heures == 19 and Minutes == 30 ) then fibaro:call(174, "pressButton", "4");
  --fibaro:debug("Moment de la journée : Soirée");
  elseif ( Heures == 0 and Minutes == 0 ) then fibaro:call(174, "pressButton", "5");
  --fibaro:debug("Moment de la journée : Nuit");
  end
end

-- Saison
local function saison(jour, mois, heures, minutes)
  if jour == 21 and heures == 0 and minutes == 0 then
    if mois == 3 then fibaro:call(176, "pressButton", "1");
      elseif mois == 6 then fibaro:call(176, "pressButton", "2");
      elseif mois == 9 then fibaro:call(176, "pressButton", "3");
      elseif mois == 12 then fibaro:call(176, "pressButton", "4");
    end -- Mois
  end -- Minuit Pile
end

-- Vérifications électriques
local function conso(time)
  local diff = time - tonumber(fibaro:getGlobalValue("DERNIER_SMS_CONSO"));
  local delai = 30*60; -- 30mn
  local ConsoCompteur = tonumber(fibaro:getValue(257,"power"));
  local ConsoFrigo = tonumber(fibaro:getValue(314,"power"));
  local ConsoSDB = tonumber(fibaro:getValue(33,"power"));
  local ConsoChambreTel = tonumber(fibaro:getValue(234,"power"));
  if ConsoFrigo < tonumber(fibaro:getGlobalValue("Seuil_Alerte_Elec")) and diff > delai then
    envoi_sms("[Domotique Info] Panne d'électricité\nConso Compteur : "..ConsoCompteur.."W\nConso Frigo/Congel : "..ConsoFrigo.."W\nConso M. à laver : "..ConsoSDB.."W\nConso Chambre : "..ConsoChambreTel.."W");
    Debug("purple","Panne de courant détectée. Message envoyé!");
    fibaro:setGlobal("DERNIER_SMS_CONSO", os.time());
  end
end

-- Boucle Principale
local function time()
  local Minutes = tonumber(os.date("%M", os.time()));
  local Heures = tonumber(os.date("%H", os.time()));

  -- On effectue les vérifications
  check(InfosPieces()); conso(os.time());
  -- Moments de la journée
  moment_journee(Heures,Minutes);
  -- Saison JJ MM hh mm
  saison(tonumber(os.date("%d")), tonumber(os.date("%m")), Heures, Minutes);
  -- Besoin de charger le téléphone ?
  if fibaro:getGlobalValue("HOME_MOMENT") ~= "Nuit" and tonumber(fibaro:getGlobalValue("CHAMBRE_Etat")) < 1 then fibaro:call(234, "turnOff"); end
  -- Si lumière allumée mais personne au domicile
  if tonumber(fibaro:getGlobalValue("Absence")) == nil and fibaro:getValue(302, "ui.labelEtat.value") == "On" then fibaro:startScene(69); end
  -- Tests SMS
  if Heures == tonumber(fibaro:getGlobalValue("HOME_TESTS_SMS")) and Minutes == 0 then envoi_sms("Test SMS Quotidien.\nIl est "..Heures.."h00"); end
  
  -- Tempo
  setTimeout(time, DELAI*1000);
end

Debug("white", "Démarrage de la scène...");

time();

 

Modifié par J3R3M
Lien vers le commentaire
Partager sur d’autres sites

Pièces 2019

Explications en construction...

 

TRIGGERS DE LA SCENE

Tous les FGMS-001, référencés dans le champ Detect de chaque pièce de T_INFOS_PIECES

Les Variables Globales gérées par les caméras dont les noms sont sous la forme CAM_CodePiece. La valeur de cette VG change à chaque détection de mouvement.

Cette scène est donc exécutée à chaque détection de mouvement dans une pièce et son nombre d'instances en conséquence.

 

  • Première étape : Détection de la pièce dans laquelle le mouvement a été détecté
  • Récupération des valeurs T_INFOS_PIECES concernant la pièce en question
  • Vérification si la pièce est une chambre et que son mode DODO est actif. Si oui -> Traitement de la scène spécifique

 

Fonction Luminosite

 

Fonction HueBtn

 

Fonction LightsOn

 

Fonction SonosAction

 

Fonction VoletsRoulants

--[[
%% properties
220 value
226 value
251 value
284 value
345 value
353 value
%% globals
CAM_ENTREE
CAM_SEJOUR
--]]

local detecteurs = {};
detecteurs[220] = "SDB";
detecteurs[226] = "SEJOUR";
detecteurs[251] = "CUISINE";
detecteurs[284] = "WC";
detecteurs[345] = "SDB";
detecteurs[353] = "CHAMBRE";

-- Debug
local debug = 1;
local function Debug(color,message)
  if debug == 1 and color ~= nil and message ~= nil then
    fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
  end
end

-- Dans quelle pièce le mouvement a-t-il été détecté?
local trigger, PIECE = fibaro:getSourceTrigger(), "";
if trigger["type"] == "property" then
  local TriggerID = trigger["deviceID"];
  PIECE = detecteurs[TriggerID];
elseif trigger["type"] == "global" then
  local triggerVAR = trigger["varName"];
  PIECE = string.gsub(triggerVAR, "CAM_", "", 1);
else
  Debug("red", "Erreur : La scène doit être démarrée par un module ou une variable!");
  fibaro:abort();
end

Debug("green", "["..PIECE.."] Un mouvement vient d'être détecté!");
fibaro:setGlobal(PIECE.."_LastMove", os.time());

-- On reforme les tableaux
local table_pieces = json.decode(fibaro:getGlobalValue("T_INFOS_PIECES"));
local minuteries = json.decode(fibaro:getGlobalValue("HOME_MINUTERIES"));
-- Infos de la pièce traitée
local INFOS = table_pieces[PIECE];
-- Variables VG
local EtatPiece = tonumber(fibaro:getGlobalValue(PIECE.."_Etat"));
local MomentJour = fibaro:getGlobalValue("HOME_MOMENT");
local HOME_DODO = tonumber(fibaro:getGlobalValue("HOME_DODO"));
local HOME_ALARME = tonumber(fibaro:getGlobalValue("HOME_ALARME"));
if HOME_DODO == 0 and INFOS.Chambre == 1 then
  if fibaro:getGlobalValue("DODO_".. PIECE) == "1" then HOME_DODO = 1; end
end

-- Fonction besoin de lumière ou non
local function luminosite()
  if type(INFOS.Detect) == "table" then
    if #INFOS.Detect == 1 and type(INFOS.Detect[1]) == "string" then
      if INFOS.JourNuit == 0 then
        Debug("white", "["..PIECE.."] [Luminosité] Détecteur = Caméra - Allumage Constant.");
        return true;
      else
        if fibaro:getGlobalValue("HOME_SOLEIL") == "0" then --and tonumber(fibaro:getGlobalModificationTime("HOME_SOLEIL")) + 60*60 <= os.time() then
          Debug("white", "["..PIECE.."] [Luminosité] Détecteur = Caméra - Allumage lorsque le soleil est couché");
          return true;
        end -- En fonction du Sunset
      end -- Fin condition Mode JourNuit
    else -- DEBUT - Plus d'un seul détecteur
      for i=1, #INFOS.Detect do
        if type(INFOS.Detect[i]) == "number" then
          if tonumber(fibaro:getValue(INFOS.Detect[i] + 2, "value")) <= tonumber(INFOS.LumMini) then
            Debug("white", "["..PIECE.."] [Luminosité] Détecteur = Motion Sensor - Besoin de lumière ("..fibaro:getValue(INFOS.Detect[i] + 2, "value").."lux).");
          return true;
          end -- Vérif valeur
        end -- Condition si c'est un FGMS
      end -- Boucle for - Détecteur par détecteur
    end -- FIN - Plus d'un seul détecteur
  end -- if type(INFOS.Detect) == "table"
  return false;
end

-- Boutons pour allumer
local function HueBtn(HueType)
  local slider = "";
  if HueType == "group" then
    slider = 10;
  elseif HueType == "hcol" then
    slider = 10;
  elseif HueType == "hwh" then
    slider = 3;
  elseif HueType == "iris" then
    slider = 10;
  end
  --Debug("grey","["..PIECE.."] [HueBtn] Bouton du VD associé à l'allumage :"..slider);
  return slider;
end -- Fin Fonction

-- Comment allume-t'on ?
local function LightsOn(moment)
  if tonumber(fibaro:getGlobalValue("HOME_DOMO")) == 1 and tonumber(fibaro:getGlobalValue(PIECE.."_Mise")) ~= 1 and EtatPiece < 2 and HOME_ALARME ~= 1 then
    -- Variables Calcul du temps depuis modificiation de VG HOME_DODO
    local delta = os.time() - tonumber(fibaro:getGlobalModificationTime("HOME_DODO"));
    local tempo = tonumber(minuteries.emmerge) * 60;

    -- Dernière extinction il y a moins du temps indiqué. On charge les dernières valeurs
    if HOME_DODO == 0 and delta > tempo
      and os.time() - tonumber(fibaro:getGlobalModificationTime(PIECE.."_Etat")) <= tonumber(fibaro:getGlobalValue("HOME_TPS_HUES"))*60 then
      
      local HueList, HueType = INFOS["HueList"], INFOS["HueType"];
      --local LastValuesHues = json.decode(fibaro:getGlobalValue("LastValues_Hues"));
      
      for i=1,#HueList do
        local HuePower = tonumber(fibaro:getGlobalValue("VDHue_"..HueList[i]));
        --local HuePower = tonumber(LastValuesHues[tostring(HueList[i])]);
        fibaro:call(HueList[i], "setSlider", HueBtn(HueType[i]), HuePower);
        --if HuePower > 0 then Debug("yellow","["..PIECE.."] [LightsOn] Lampe "..HueList[i].." allumée à "..HuePower.."%."); end
        Debug("yellow","["..PIECE.."] [LightsOn] Lampe "..HueList[i].." allumée à "..HuePower.."%.");
      end -- Boucle lampe par lampe
    -- Pas de mouvement dans la pièce depuis plus du temps indiqué, on cherche les valeurs par défaut
    else
      local emmerge = 1;
      local tPower = "";

      if HOME_DODO == 0 then
        tPower = INFOS["HuePower"..moment];
        if delta <= tempo then emmerge = tonumber(fibaro:getGlobalValue("PuissanceEmmerge"))/100 end
      else
        tPower = INFOS["HuePowerDodo"];
      end
 
      if luminosite() then
        if #tPower == 1 then
          local HueGroup = INFOS["HueGroup"];
          for i=1,#HueGroup do
            fibaro:call(HueGroup[i], "setSlider", "10", math.floor(tPower[1] * emmerge));
            Debug("yellow","["..PIECE.."] [LightsOn] Groupe Hue ("..HueGroup[i]..") de la pièce allumé.");
          end -- Boucle groupes
        else
          local HueList, HueType = INFOS["HueList"], INFOS["HueType"];
          for i=1,#HueList do
            fibaro:call(HueList[i], "setSlider", HueBtn(HueType[i]), math.floor(tPower[i] * emmerge));
            Debug("yellow","["..PIECE.."] [LightsOn] Lampe "..HueList[i].." allumée.");
          end -- Boucle lampe par lampe
        end -- Condition tPower = 1
      else
        Debug("yellow","["..PIECE.."] [LightsOn] Pas besoin d'éclairage.");
      end -- Luminosite()
    end -- Mode lumière : Preset ou dernières valeurs
  else
    Debug("red","["..PIECE.."] [LightsOn] Pas besoin d'éclairage.");
    if tonumber(fibaro:getGlobalValue("HOME_DOMO")) ~= 1 then Debug("white","["..PIECE.."] [LightsOn] HOME_DOMO = 0 (Valeur 1 nécessaire)"); end
    if tonumber(fibaro:getGlobalValue(PIECE.."_Mise")) == 1 then Debug("white","["..PIECE.."] [LightsOn] "..PIECE.."_Mise = 1 (Valeur 0 nécessaire)"); end
    if EtatPiece >= 2 then Debug("white","["..PIECE.."] [LightsOn] EtatPiece = "..EtatPiece.." (Valeur <2 nécessaire)"); end
    if HOME_ALARME == 1 then Debug("white","["..PIECE.."] [LightsOn] HOME_ALARME = 1 (Valeur 0 nécessaire"); end
  end -- Condition DOMO & Mise
end -- Fin Fonction

-- Fonction SONOS Follow
local function SonosAction(id,piece,sonosV)
  if fibaro:getGlobalValue('HOME_SONOS_FOLLOW') == "1" and #id > 0 and HOME_DODO == 0 and HOME_ALARME ~= 1
    and EtatPiece ~= 2 and fibaro:getGlobalValue(PIECE.."_Mise") ~= "1" then
    if os.time() - tonumber(fibaro:getGlobalValue(piece.."_LastMove")) <= tonumber(fibaro:getGlobalValue("HOME_TPS_SONOS"))*60 then -- Enregistrement pendant 1h
      --local LastValuesSonos = json.decode(fibaro:getGlobalValue("LastValues_Sonos"));
      for i=1,#id do
        local lastlvl = tonumber(fibaro:getGlobalValue("VDSonos_"..id[i]));
        --local lastlvl = tonumber(LastValuesSonos[tostring(id[i])]);
        if tonumber(fibaro:getValue(id[i], "ui.slVolume.value")) < lastlvl then
          fibaro:call(id[i], "setSlider", "10", lastlvl);
          Debug("lightgreen","["..piece.."] [Sonos "..id[i].."] Volume de l'enceinte "..i.."/"..#id.." restitué ("..lastlvl.."%)");
        end -- Vérification Niveau
      end -- Boucle FOR pour chaque Sonos
    else -- Pas de mouvement dans la pièce depuis plus du temps indiqué
      for i=1,#id do
        if tonumber(fibaro:getValue(id[i], "ui.slVolume.value")) < sonosV then
          fibaro:call(id[i], "setSlider", "10", sonosV);
        end -- Si volume plus bas que prévu, on augmente
      end -- Boucle FOR pour chaque Sonos
      Debug("lightgreen","["..piece.."] [SonosAction] Volume des enceintes augmenté");
    end -- Mouvement depuis moins de 20mn
  end -- follow == 1
end -- Fonction

-- Fonction Volets Roulants
local function VoletsRoulants(var,valeur)
  if fibaro:getGlobalValue("HOME_SOLEIL") == "1" and fibaro:getGlobalValue("HOME_DODO") == "0"
  and fibaro:getGlobalModificationTime("HOME_SOLEIL") <= os.time()-minuteries.sunset*60 then
    if var ~= nil and type(var) == "table" then
      for i=1,#var do
        fibaro:call(var[i], "setValue", tonumber(valeur));
        Debug("green","[VoletsRoulants] de "..INFOS.Article..INFOS.Nom.." ouverts.");
      end -- Boucle volet par volet
    end -- Il y a des volets dans la pièce
  end -- Nécessité d'ouvrir les volets ?
end

-- On allume si nécessaire
LightsOn(MomentJour);

-- SONOS
fibaro:killScenes(INFOS.SonosFadeOut);
SonosAction(INFOS.SonosId,INFOS.Code,INFOS.SonosV[MomentJour]);

-- Volets Roulants
VoletsRoulants(INFOS.VoletsR,0);

-- Démarrage du REC si nécessaire
if tonumber(fibaro:getGlobalValue('REC_OFF')) <= os.time() and tonumber(fibaro:getGlobalValue("NETATMO_Presents")) < 1 and
 ( HOME_DODO == 0 or ( HOME_DODO == 1 and INFOS.Chambre ~= 1 ) )
then fibaro:call(155, "pressButton", "1"); end

-- On met à jour la variable pièce
fibaro:call(199, "pressButton", INFOS.id);
-- Variable Dernier Mouvement
fibaro:setGlobal(PIECE.."_Etat", 2);
fibaro:setGlobal("DernierMouvement", os.time());

 

Modifié par J3R3M
Lien vers le commentaire
Partager sur d’autres sites

NetAtmo Welcome

Explications à venir...

 

--[[
%% globals
DernierMouvement
--]]


-- Informations de compte Netatmo
local client_id = '';
local client_secret = '';
local username = '';
local password = '';

-- Informations du VD associé
local vd_ID = 304; 
local vd_refresh = 9;

-- Réglages de la scène
local refresh = 2; -- Script executé toutes les x secondes. Pas moins de 8s!
local debug = 0; -- Faut-il vraiment l'expliquer ?

-- Nom de la Variable Globale qui sera créée et utilisée par la scène et le VD
local VGNetatmo = "NETATMO_Welcome";

--------------------------------------------------------------
-------- Ne rien modifier à partir de cette ligne ------------
--------------------------------------------------------------
local token = '';
local request_body = '';

Debug = function (color, message)
  if (debug == 1) then
    fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
  elseif (debug == 0) then
  end
end

DebugChange = function (color, message)
  fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
end

DebugError = function (color, message)
  fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
end

-- Envoi SMS
local function envoi_sms(sms)
  if os.time() - fibaro:getGlobalModificationTime("DERNIER_SMS") > 20*60 then
    local char_to_hex = function(c) return string.format("%%%02X", string.byte(c)) end
    local function urlencode(url)
      if url == nil then return end
      url = url:gsub("\n", "\r\n")
      url = url:gsub("([^%w ])", char_to_hex)
      url = url:gsub(" ", "+")
      url = url:gsub(">", "%0A")
      return url
    end
  local url = "http://192.168.2.14:9090/send.html?smsto=+336********&smstype=sms&smsbody="..urlencode(sms);
  http:request(url, { options = { method = 'GET', data = json.encode(newVar)}});
  fibaro:setGlobal("DERNIER_SMS", os.time());
  else
    Debug("grey", "Un message n'a pas été envoyé en raison du temps défini entre les SMS.");
  end
end

-- Fonction Que faire en fonction des personnes reconnues
function Action(qui)
  -- Si scène intrusion active
  if fibaro:countScenes(141) > 0 then
    -- Jérémy
    if qui == "Jérémy" then
      Debug("grey", "Démmarrage -> Actions prévues pour Jérémy");
      StreamSonos(245,"local","//JEREM-NAS/music/HC2/Reconnu.mp3",50);
      fibaro:call(163, "pressButton", 1); -- VD Présence
      fibaro:setGlobal("HOME_ALARME", 0);

    -- Emilie
    elseif qui == "Emilie" then
      Debug("grey", "Démmarrage -> Actions prévues pour Emilie");
      StreamSonos(245,"local","//JEREM-NAS/music/HC2/Reconnu.mp3",50);
      envoi_sms("[Domotique Info] Emilie est à la maison!");
      fibaro:call(282, "pressButton", 1); -- VD Présence
      fibaro:setGlobal("HOME_ALARME", 0);

    -- Maman ou Gilles
    elseif qui == "Maman" or qui == "Gilles" then
      Debug("grey", "Démmarrage -> Actions prévues pour Maman");
      StreamSonos(245,"local","//JEREM-NAS/music/HC2/Maman.mp3",40);
      envoi_sms("[Domotique Info] Maman est à la maison!");
      fibaro:setGlobal("HOME_ALARME", 0);

    -- Personnes autorisées sans action spécifique
    elseif qui == "Déborah" or qui == "Maélys" or qui == "Célia" then
      Debug("grey", "Démmarage -> Actions prévues pour les personnes autorisées.");
      StreamSonos(245,"local","//JEREM-NAS/music/HC2/Reconnu.mp3",40);
      envoi_sms("[Domotique Info] Une personne autorisée a été reconnue.");
      fibaro:setGlobal("HOME_ALARME", 0);

    -- Autres non autorisés
    else
      if fibaro:getGlobalValue("PRESENCE_JEREMY") == "0" and fibaro:getGlobalValue("PRESENCE_EMILIE") == "0" then
        DebugChange("orange", "Visage reconnu, mais personne non-autorisée à pénétrer seule dans l'appartement.");
        envoi_sms("[Domotique Info] Une personne non-autorisée a été reconnue.");
        fibaro:setGlobal("HOME_ALARME", 1);
      end -- Condition Propriétaires absents
    end -- Conditions personnes par personnes
    fibaro:killScenes(141);  -- On tue la scène intrusion
  end -- Scène intrusion active
end -- Fonction

-- Fonction Stream Sonos
function StreamSonos(VD_ID,Source,Stream,Volume,Duree)
  local params = {
    stream = tostring(Stream),
    source = tostring(Source),
    duration = tonumber(Duree),
    volume = tonumber(Volume)};
  local _f = fibaro;
  local _x ={root="x_sonos_object",load=function(b)local c=_f:getGlobalValue(b.root)if string.len(c)>0 then local d=json.decode(c)if d and type(d)=="table"then return d else _f:debug("Unable to process data, check variable")end else _f:debug("No data found!")end end,set=function(b,e,d)local f=b:load()if f[e]then for g,h in pairs(d)do f[e][g]=h end else f[e]=d end;_f:setGlobal(b.root,json.encode(f))end,get=function(b,e)local f=b:load()if f and type(f)=="table"then for g,h in pairs(f)do if tostring(g)==tostring(e or"")then return h end end end;return nil end}
  _x:set(tostring(VD_ID), { stream = params });
  _f:call(tonumber(VD_ID), "pressButton", 20);
end

-- Ajout pour gestion indépendante des VG
function CreerVG(VGNom, VGValeur)
  local data = {name = VGNom, value=VGValeur};
  response, status = api.post("/globalVariables", data);
  if (status == 201) then
    DebugError("white", "Variable Globale " .. VGNom .. " créée.");
    created = true;
  else
    DebugError("red", "Impossible de créer la Variable Globale " .. VGNom .. "!");
  end
end

function MajEntree(Nom, ID, Statut, Lastseen)
  local table = json.decode(fibaro:getGlobalValue(VGNetatmo));

  -- Tout est à mettre à jour
  if Nom ~= nil and ID ~= nil and Statut ~= nil and Lastseen ~= nil then
    table[Nom] = {id=ID, status=Statut, lastseen=Lastseen};
    fibaro:setGlobal(VGNetatmo,json.encode(table));
    DebugError("yellow", "L'entrée " .. Nom .. " a été automatiquement créée.");
  -- Mise à jour du Statut
  elseif Nom ~= nil and Statut ~= nil and Lastseen == nil then
    table[Nom].status = Statut;
    fibaro:setGlobal(VGNetatmo,json.encode(table));
    Debug("yellow", "Le statut de " .. Nom .. " a été mis sur la valeur ".. Statut);
  -- Mise à jour de la dernière vue de la personne
  elseif Nom ~= nil and Statut == nil and Lastseen ~= nil then
    table[Nom].lastseen = Lastseen;
    fibaro:setGlobal(VGNetatmo,json.encode(table));
    Debug("yellow", "L'information 'lastseen' de " .. Nom .. " a été mise sur la valeur ".. Lastseen);
  else
    DebugError("red", "Erreur lors de l'utilisation de la fonction MajEntree");
    if Nom == nil then DebugError("white", "Champ 'Nom' vide !"); end
    if Statut == nil then DebugError("white", "Champ 'Statut' vide !"); end
    if Lastseen == nil then DebugError("white", "Champ 'Lastseen' vide !"); end
  end
end

if fibaro:getGlobalValue(VGNetatmo) == nil then CreerVG(VGNetatmo,json.encode({})); end
-- Fin - Ajout pour gestion indépendante des VG

function oAuth(nextFunction)
  local request_body = 'grant_type=password&client_id=' .. client_id .. '&client_secret=' .. client_secret .. '&username=' .. username .. '&password=' .. password .. '&scope=read_camera%20write_camera';
  getResponseData('https://api.netatmo.net/oauth2/token', request_body, 
    function(data) 
      if (data.access_token ~= nil) then
        token = data.access_token
        fibaro:setGlobal("NETATMO_Token",token);
      	gethomedata()
      else
        DebugError( "red", "Impossible de joindre l'API!");
      end
    end
    )
  --setTimeout(oAuth, refresh*1000);
end

function getResponseData(url, body, func)
  local http = net.HTTPClient();
    http:request(url, { 
      options = { 
      method = 'POST', 
      headers = {['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'},
      data = body,
      checkCertificate = false
      },
    success = function(response);
    func(json.decode(response.data));
  end
  })   
end

function gethomedata()
  request_body_cam = 'access_token=' ..token.. '';
  getResponseData('https://api.netatmo.net/api/gethomedata', request_body_cam, 
    function(getData)
      if (getData.body ~= nil) then
        for w, v in pairs(getData.body.homes) do
          for a, b in pairs(v.persons) do
            local INFOS = json.decode(fibaro:getGlobalValue(VGNetatmo));
        	if (b.pseudo ~= nil) then
             if (b.out_of_sight == false) then
                if INFOS[b.pseudo] ~= nil then
                  MajEntree(b.pseudo,b.id,nil,b.last_seen);
                  local change_var = tonumber(INFOS[b.pseudo].status);
                  if (change_var == 0) then
                     DebugChange("green", b.pseudo.. ' est présent.');
                     MajEntree(b.pseudo,b.id,1,nil); Action(b.pseudo);
                   else
                     Debug("white", b.pseudo.. ' est toujours présent.');
                   end 
                else
                  Debug("red", "L'entrée pour " ..b.pseudo.. " de la table "..VGNetatmo.." n'éxiste pas.");
                  MajEntree(b.pseudo,b.id,0,0);
                end
             else
                if INFOS[b.pseudo] ~= nil then
                  MajEntree(b.pseudo,b.id,nil,b.last_seen);
                  local change_var2 = tonumber(INFOS[b.pseudo].status);
                  if (change_var2  == 1) then
                     DebugChange( "orange", b.pseudo.. ' est absent.');
                     MajEntree(b.pseudo,b.id,0,nil);
                   else
                     Debug( "white", b.pseudo.. ' est toujours absent.');
                   end
                else
                  Debug("red", "L'entrée pour " ..b.pseudo.. " de la table "..VGNetatmo.." n'éxiste pas.");
                  MajEntree(b.pseudo,b.id,0,0);
                end
             end
          end
      	end
      end
    else 
        Debug("red", "Impossible de joindre l'API! Vérifier le taux de rafraichissemment!");
    end
  if tonumber(vd_ID) ~= nil then fibaro:call(vd_ID, "pressButton", vd_refresh); end
  end
 )
end

-- Nb de connexions à l'API ce jour
local Compteur = tonumber(fibaro:getGlobalValue("NETATMO_Compteur"));

-- Fonction oAuth + refresh
local function oAuthRefresh()
  -- Vérification du nombre de personnes détectées
  local Welcome_PA = tonumber(fibaro:getGlobalValue("NETATMO_Presents"));
  local Jeremy = tonumber(fibaro:getGlobalValue("PRESENCE_JEREMY"));
  local Emilie = tonumber(fibaro:getGlobalValue("PRESENCE_EMILIE"));
  local NbPresents = Welcome_PA+Jeremy+Emilie;

  if fibaro:countScenes(141) > 0 and os.time() - tonumber(fibaro:getGlobalValue("DernierMouvement")) < 60 then -- Si la scène intrusion est active
    if Compteur < 4000 then
      fibaro:setGlobal("NETATMO_Compteur", Compteur+1);
      Debug("white", "Scène démarrée et executée toutes les "..refresh.."s.");
      oAuth(); setTimeout(oAuthRefresh, refresh*1000);
    else
      Debug("red", "Nombre maximum de connexions à l'API atteint!");
    end
  -- Mise à jour du nombre de présents
  elseif Welcome_PA < 3 then
    if Compteur < 4000 then
      oAuth();
      fibaro:setGlobal("NETATMO_Compteur", Compteur+1);
      Debug("grey", "Informations NetAtmo mises à jours dans la base de données.");
    else
      DebugError("red", "Nombre maximum de connexions à l'API atteint!");
    end
  -- Vérifications régulières
  elseif NbPresents >= 1 and os.time() - tonumber(fibaro:getGlobalModificationTime(VGNetatmo)) > 10*60 then
    if Compteur < 4000 then
      oAuth();
      fibaro:setGlobal("NETATMO_Compteur", Compteur+1);
      Debug("grey", "Informations NetAtmo mises à jours dans la base de données.");
    else
      DebugError("red", "Nombre maximum de connexions à l'API atteint!");
    end
  -- Vérification effectuée il y a peu, on ne met pas à jour
  else
    Debug("grey", "Inutile d'effectuer une mise à jour des valeurs Welcome.");
  end
end

local trigger = fibaro:getSourceTrigger();

if trigger["type"] == "global" then
  oAuthRefresh();
else
  oAuth(); fibaro:setGlobal("NETATMO_Compteur", Compteur+1);
  local Welcome_PA = tonumber(fibaro:getGlobalValue("NETATMO_Presents"));
  if Welcome_PA == 1 then
    DebugChange("lightblue", "[".. os.date("%a %d %B") .."] Une personne présente");
  elseif Welcome_PA > 1 then
    DebugChange("lightblue", "[".. os.date("%a %d %B") .."]" .. Welcome_PA.." personnes présentes.");
  else
    DebugChange("red", "[".. os.date("%a %d %B") .."] Tout le monde absernt du domicile.");
  end
end

 

Modifié par J3R3M
Lien vers le commentaire
Partager sur d’autres sites

VD Etat Pièces

Explications à venir...

 

CODE MAINLOOP

local RecupValeursHues = "API"; -- VD ou API
local HueUser = fibaro:getGlobal('VD_Hue_User');
local table_pieces = json.decode(fibaro:getGlobalValue("T_INFOS_PIECES"));
local minuteries = json.decode(fibaro:getGlobalValue("HOME_MINUTERIES"));
local Welcome_PA = tonumber(fibaro:getGlobalValue("NETATMO_Presents"));
local Manuel_PA = tonumber(fibaro:getGlobalValue("NB_PIECES_ACTIVES"));
local TpsMini = minuteries.lightsp;
local tTri = {};
local PA = 0;
local VirtualPa = 1;
local HueCMD = Net.FHttp("192.168.2.21",80);

-- Debug
local debug = 1;
local function Debug(color,message)
  if debug == 1 and color ~= nil and message ~= nil then
    fibaro:debug("[DEBUG] " .. string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
  end
end

-- Info
local function Info(color,message)
  if color ~= nil and message ~= nil then
    fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"));
  end
end

-- Récupération et tri des derniers mouvements
for k,v in pairs(table_pieces) do
  table.insert(tTri, {code=v.Code, last=fibaro:getGlobalValue(v.Code.."_LastMove"), passage=v.Passage, tpsActive=v.TpsActive});
end
table.sort(tTri, function(a, b) return a.last > b.last end);

-- Cb de pièces actives actuellement ?
if Manuel_PA ~= nil then PA = Manuel_PA; else PA = Welcome_PA; end

-- Boutons luminosité
local function HueBtn(HueType)
  local slider = "";
  if HueType == "group" then slider = 10;
  elseif HueType == "hcol" then slider = 10;
  elseif HueType == "hwh" then slider = 3;
  elseif HueType == "iris" then slider = 10; end
  Debug("white","[HueBtn] ID du Slider (Type = "..HueType..") : "..slider);
  return slider;
end

-- Fonction de recherche des valeurs d'un tableau par rapport à celles d'un autre
local function TableMatch(ceci,cela) -- Rechercher valeurs de ceci dans cela
  for i=1,#ceci do
    for j=1,#cela do
      if ceci[i] == cela[j] then Debug("yellow","[TableMatch] VD "..ceci[i].." utilisé dans plusieurs pièces."); return true; end
    end
  end
  return false;
end

-- Fonction Extinction
local function Action(Code,Etat)
  local INFOS = table_pieces[Code];
-- Pièce allumée ?
  local HueGroup = INFOS["HueGroup"];
  local HuesOn = false;
  for i=1,#HueGroup do
    local etat = fibaro:getValue(HueGroup[i], "ui.labelEtat.value");
    if etat == "On" then HuesOn = true; end
  end
-- Fade
  if Etat == 1 then
    --local LastValuesHues = {};
    local HueUser = fibaro:getGlobal('VD_Hue_User');
    local HueList, HueType = INFOS["HueList"], INFOS["HueType"];
    -- Traitement Hues
    for i=1,#HueList do
      -- Récupération via VD
      if RecupValeursHues == "VD" then
        local val = tonumber(fibaro:getValue(HueList[i], "ui.Luminosite.value"));
        if val > 0 then
          fibaro:call(HueList[i], "setSlider", HueBtn(HueType[i]), val/2);
          Info("lightblue","["..Code.."] [Ampoule "..HueList[i].."] Valeur "..val.." enregistrée et puissance atténuée");
        end -- if val > 0
        fibaro:setGlobal("VDHue_"..HueList[i], val);

      -- Récupération via API
      else
        local response ,status, errorCode = HueCMD:GET('/api/'..HueUser..'/lights/'..fibaro:get(HueList[i], 'TCPPort'));

        if (tonumber(status) == 200) then 
          local jsonTable = json.decode(response);
	      -- Vérification si des erreurs existent dans le tableau 
	      if (jsonTable[1] ~= nil) then
   	        -- Affichage des informations de l'erreur
   	        errorType = jsonTable[1].error.type;
            errorDescription = jsonTable[1].error.description;
            fibaro:debug("Error type = "..errorType);
            fibaro:debug("Error description = "..errorDescription); 
            if (errorType == 1) then fibaro:log("Hue: Utilisateur Non Autorisé");
            elseif (errorType == 3) then fibaro:log("Hue: n° ID Incorrect"); end 
	      -- Récupération des informations via Json
          else
            local val = 0;
            if jsonTable.state.on then
              val = math.floor(tonumber(jsonTable.state.bri)/2.54);
              fibaro:call(HueList[i], "setSlider", HueBtn(HueType[i]), val/2);
              --HueCMD:PUT('/api/'..HueUser..'/lights/'.. fibaro:get(HueList[i], 'TCPPort') ..'/state', '{"on":true, "bri":'.. val/2 ..'}');
              Info("lightblue","["..Code.."] [Ampoule "..HueList[i].."] Valeur "..val.." enregistrée et puissance atténuée");
            end -- if jsonTable.state.on == "true"
            fibaro:setGlobal("VDHue_"..HueList[i], val);
          end -- if (jsonTable[1] ~= nil)
        end -- if (tonumber(status) == 200)
      end -- Condition RecupValeursHues
    end -- Boucle Ampoule par ampoule
    fibaro:setGlobal(Code.."_Etat", 1);

-- Extinction
  elseif Etat == 0 then
    -- Traitement Hues
    if HuesOn then
      for i=1,#HueGroup do
        fibaro:call(HueGroup[i], "pressButton", "44");
        Info("orange","["..Code.."] [Groupe "..HueGroup[i].."] Ampoules du groupe éteintes.");
      end
    end
    -- Traitement Sonos
    local Sonos = INFOS["SonosId"];
    if fibaro:getGlobalValue('HOME_SONOS_FOLLOW') == "1" and fibaro:getGlobalValue('HOME_DODO') ~= "1" and #Sonos > 0 then
      -- On liste tous les IDs Sonos sans ceux de la pièce en cours
      local TableSonos = {};
      for k,v in pairs(table_pieces) do
        if k ~= Code and tonumber(fibaro:getGlobalValue(k.."_Etat")) > 0 then
          for i=1,#v.SonosId do
            table.insert(TableSonos, v.SonosId[i]);
            Debug("white", "["..k.."] ID VD Ajouté à la table TableSonos : ".. v.SonosId[i]);
          end -- for i=1
        end -- if k k ~= Code
      end -- for k,v

      -- Si le VD n'est pas utilisé dans une pièce active, on l'atténue à 5%
      if not TableMatch(Sonos,TableSonos) then
        fibaro:startScene(INFOS.SonosFadeOut);
        --local LastValuesSonos = {};
        --[[for i=1,#Sonos do
          fibaro:call(Sonos[i], "setSlider", "10", "5");
          Info("lightgreen","["..Code.."] [Sonos "..Sonos[i].."] Enceinte atténuée à 5%.");
        end]]--
        --fibaro:setGlobal("LastValues_Sonos", json.encode(LastValuesSonos));
      else
        Debug("green","["..Code.."] Les enceintes de cette pièce sont aussi affectées à une autre pièce.");
      end
    end
    -- VG Etat Pièce
    fibaro:setGlobal(Code.."_Etat", 0);
  end
end

-- Traitement des Infos
local function CountDown(Code,Last,Tps)
  local Aff = "";
  if fibaro:getGlobalValue(Code.."_Mise") ~= "1" then -- Si pas de mise dans la pièce
    local delta = Tps*60 - (os.time() - Last);

    if delta >= 0 then -- Temps restant positif, on affiche le décompte
      Aff = delta.." s";
    else -- Temps restant dépassé
      -- Fade
      if delta >= -10 or fibaro:getGlobalValue(Code.."_Etat") == "2" then
        if fibaro:getGlobalValue(Code.."_Etat") ~= "1" then
          Aff = "Fade";
          Action(Code,1);
        else
          Aff = "Tamisé";
        end
      -- Extinction
      elseif delta < -10 and fibaro:getGlobalValue(Code.."_Etat") == "1" then
        Aff = "Extinction";
        Action(Code,0);
      -- Pièce inactive
      else
        Aff = "-";
      end
    end -- Affichages
  else
    Aff = "Mise Activée";
  end
  fibaro:call(fibaro:getSelfId(), "setProperty", "ui.".. Code ..".value", Aff);
end

-- Affichage
if PA > 1 then
  VirtualPa = PA;
  for i=1,PA do if tTri[i].passage == 1 and i ~= 1 and VirtualPa < #tTri then VirtualPa = VirtualPa+1; end end
end

for i=1,#tTri do
  if i <= VirtualPa then
    if tTri[i].passage == 1 and i > 1 then CountDown(tTri[i].code,tTri[i].last,TpsMini);
    elseif i == 1 and tTri[i].code ~= "ENTREE" then
      fibaro:call(fibaro:getSelfId(), "setProperty", "ui.".. tTri[i].code ..".value", "Active");
    else CountDown(tTri[i].code,tTri[i].last,tTri[i].tpsActive); 
    end -- Conditions CountDown
  else
    CountDown(tTri[i].code,tTri[i].last,TpsMini);
  end -- Valeur de i
end -- Boucle

-- Message pour WatchDog
Info("black","Check");

 

Lien vers le commentaire
Partager sur d’autres sites

VDs de paramétrage

Explications à venir...

Administration.png.0713f1e930347461db4d3515ed7cb7c5.png

 

VD MINUTERIES

Ce VD permet de saisir les informations de temps qui seront exploitées par la HC2.

Ces informations sont encapsulées dans un JSON puis enregistrées dans la VG HOME_MINUTERIES.

  • lightsp : Les lumières resteront allumées cette durée au minimum (Lights Présence car, auparavant, j'avais aussi créé une valeur en cas d'absence de ma compagne ou moi-même. Notion que j'ai supprimé depuis.)
  • sms durée minimale entre deux envois de SMS de la part de la HC2
  • emmerge Durée durant laquelle la HC2 restera en mode Émergement après la sortie du mode DODO. Ce mode émergement adapte notamment la puissance des éclairages.
  • sunset Durée après le coucher du soleil pendant laquelle la HC2 considèrera qu'il fait encore jour

764745491_VDMinuteries.png.fb4ff3d6d9ecc4d8034129902da47f6f.png

 

VD MOMENT DE LA JOURNÉE

Directement géré et exploité par les scènes. Ces informations sont enregistrées dans la VG HOME_MOMENT.

213024016_VDMomentdelajournee.png.8bcdc2f6ccb2071d7638dbeea4139120.png

VD PIECE ACTIVE

Directement géré et exploité par les scènes. Un appui sur un bouton change la valeur de VG PIECE_ACTIVE et effectue éventuellement les actions propres à cette pièce.

318656780_VDPieceActive.png.12bc70c859c4c7fa4922ad3b6ebb88e7.png

VD SAISON

Directement géré par les scènes. Un appui sur un bouton change la valeur de VG HOME_SAISON et effectue éventuellement les actions propres à cette saison.

La saison n'est exploitée nul part... Mais elle est là, au cas-où...

1223281592_VDSaison.png.b94840acac8c725eb847625a2854b65f.png

VD TEMPÉRATURES

Ce VD permet de saisir les informations de températures qui seront surveillées par la HC2.

Ces informations sont encapsulées dans un JSON puis enregistrées dans la VG T_TEMPERATURES.

  • mini Température minimale
  • maxi Température maximale

1228680503_VDTemperatures.png.102ba1325eb7e7c731f59bfb99826802.png

 

VD TESTS SMS

Ce VD gère l'heure à laquelle sera envoyé le sms de test journalier provenant de la HC2. Exploite la VG HOME_TESTS_SMS

532419697_VDTestsSMS.png.dff3fef5904e135c544fe42e2cb0b656.png

 

Modifié par J3R3M
  • Upvote 1
Lien vers le commentaire
Partager sur d’autres sites

Variables Globales

Repérées en vert dans les précédentes explications

 

  • Absence Contient la donnée os.tilme() du dernier mouvement détecté, sauf si le mode Absence est enclenché (automatiquement ou manuellement)
  • DernierMouvement Contient la donnée os.time() du dernier mouvement détecté, peu importe la pièce
  • DERNIER_SMS Contient la donnée os.time() du dernier SMS envoyé par la HC2
  • DERNIER_SMS_CONSO Contient la donnée os.time() du dernier SMS concernant un défaut d'électricité envoyé par la HC2
  • HOME_DODO Mode Sommeil de l'appartement (0/1)
  • HOME_MINUTERIES Tableau JSON exploité par le VD Minuteries
  • HOME_MOMENT Moment de la journée AM - Midi - PM - Soir - Nuit. Exploité par le VD Moment de la journée
  • HOME_SAISON Saison de l'année. Exploitée par le VD Saison
  • HOME_TESTS_SMS Contient l'heure à laquelle le SMS de test sera envoyé par la HC2. Si la VG contient une valeur string, les tests sont désactivés. Exploité par le VD TEST SMS
  • NETATMO_Compteur VG contenant le nombre d'appels à l'API NetAtmo effectués dans la journée. Nombre d'appels maxi fixés à 4000.
  • PIECE_ACTIVE Contient le code de la dernière pièce ayant détecté un mouvement. Exploité par le VD Pièce Active
  • Seuil_Alerte_Elec Valeur minimum qui doit être consommée par le frigo. En dessous de cette valeur, une notification sera retournée via la scène Check 1mn
  • T_INFOS_PIECES Tableau JSON contenant toutes les informations des pièces : Nom, Devices, Eclairages, Enceintes...
  • T_TEMPERATURES Tableau JSON contenant les valeurs de températures

 

Variables par Pièce de l'appartement :

  • NomPièce_Mise Etat lumineux enregistré pour une pièce. Une mise à 1 désactive l'extinction automatique de la lumière si aucun mouvement
  • NomPièce_Etat Etat de la pièce : 0 Eteinte - 1 dimmée à 50% - 2 allumée

 

Variables par Chambre de l'appartement :

Rappel, une chambre est considérée comme telle par les scènes si la valeur de la Chambre dans T_INFOS_PIECES = 1

  • DODO_NomChambre 0/1
Modifié par J3R3M
Lien vers le commentaire
Partager sur d’autres sites

Il y a 15 heures, Nico a dit :

Hâte de lire les explications !

J'espère avoir le temps de finir ça avant la fin du confinement... En y allant petit à petit, je me rends compte que c'est un boulot de dingue d'expliquer tout ça, alors qu'il n'y a pas grand chose.

Un autre boulot de dingue : me souvenir ce que j'ai fait et pourquoi :huh: Tout en me rendant compte de certaines incohérences :2:

Lien vers le commentaire
Partager sur d’autres sites

Il y a 9 heures, J3R3M a dit :

J'espère avoir le temps de finir ça avant la fin du confinement...

 Ne t'en fais pas, on va en reprendre encore une couche.

 

Lien vers le commentaire
Partager sur d’autres sites

×
×
  • Créer...