Aller au contenu

Rechercher dans la communauté

Affichage des résultats pour les étiquettes 'Tuto HC2'.



Plus d’options de recherche

  • Rechercher par étiquettes

    Saisir les étiquettes en les séparant par une virgule.
  • Rechercher par auteur

Type du contenu


Forums

  • Bienvenue
    • Nouveau ? Présentez-vous
    • Le bistrot
    • Mon installation domotique
    • Annonces et suggestions
  • La Home Center et ses périphériques
    • La Home Center pour les nuls
    • HC 2 & Lite
    • HC 3
    • Modules Fibaro
    • Modules Z-wave
    • Périphériques et matériels autres
    • Plugins
    • Quick App
    • Multimédia (audio, vidéo ...)
    • Chauffage et Energie
    • Actionneurs & Ouvrants (Portail, volets, piscines, ...)
    • Eclairage
    • Applications Smartphones et Tablettes
  • Autres solutions domotiques
    • Box / Logiciel
    • Modules Nice (433 & 866 MHz)
    • Modules Zigbee
    • GCE Electronics
    • Modules Bluetooth Low Energy
  • Objets connectés
    • Les Assistants Vocaux
    • Netatmo
    • Philips Hue
    • DIY (Do It Yoursel)
  • Sécurité
    • Sécurité (Alarmes, Caméras, Portiers)
    • Alarmes
    • Caméras
    • Portiers
    • Serrures
  • Informatique / Réseau
    • Tutoriels
    • Matériels Réseaux
    • Matériels Informatique
    • NAS
    • Virtualisation
  • Les bonnes affaires
    • Sites internet
    • Petites annonces

Rechercher les résultats dans…

Rechercher les résultats qui…


Date de création

  • Début

    Fin


Dernière mise à jour

  • Début

    Fin


Filtrer par nombre de…

Inscription

  • Début

    Fin


Groupe


Jabber


Skype


Ville :


Intéret :


Version

105 résultats trouvés

  1. EDIT : VD disponibles dans les pages suivantes Ce tuto est un projet qui démarre, il n'y a encore rien à partager... Mais vu la saison, j'ai la pression. Le but du virtal device est de simplifier la gestion de la piscine, en commençant par la filtration. Pour le moment je débute en LUA et VD et je m'attaque à la logique avant de l'enrober dans un VD ou plugin. La partie logique ne devrait pas trop poser de problème mais l'absence de fonctions partagées sur la HC2 rends les codes peu digeste à priori un peu de théorie: Vous trouverez plein de sites qui traitent de la filtration piscine allant du simple 'température / 2' à des notions plus complexes. Je me base sur la notion de 'durée de cycle' pour régler le temps de marche de la pompe. En effet dans l'absolu le temps n'est pas un bon critère car tout dépend du dimensionnement de la filtration versus le volume de la piscine. Une règle de base répandue sur le net donne Eau > 25 °C : on conseille 3 cycles complets de filtration, au minimum 12 h. 20 °C < eau < 24 °C : compter environ 1 à 2 cycles de filtration soit de 10 à 11 h. 15 °C < eau < 20 °C : 1 cycle complet suffit. 10 °C < eau < 14 °C : ½ voire même ¼ de cycle dans ce cas, ce qui dure approximativement entre 1 et 2 h. Eau < 10 °C : dans ce cas la filtration quotidienne est facultative. Avec un peu de lissage on obtient une courbe température / cycles (donc durée) de la forme Cette courbe n'est pas linéaire mais sans entrer dans les détails elle reste un cas général à adapter à chaque bassin (type désinfection, fréquentation moyenne, environnement....) Je propose de ne pas trop discuter la forme/hauteur de la courbe sur ce forum... De toute façon le VD permettra de fixer votre courbe de référence allant de la simple droite à une forme ultra 'optimisée'. des choix à faire: Vous trouverez de tout comme stratégie pour économiser/optimiser perso je suis plutôt contre la filtration de nuit en HC... - bon et au final + cher filtrer X minutes par heure pour atteindre la durée totale me parait moyen aussi pour mon algo (à créer) je pars sur - 1 à 3 périodes de filtration par jour - filtrer plus en fin de journée pour compenser la fréquentation et assurer un bon nettoyage avant le repos nocturne - j'ai des HC entre 12h et 13h30 autant filtrer (il n'y a pas de petites économies). De plus avoir une filtration fixe vers midi permettra de prendre une température de référence cohérente de jour en jour en plus de la gestion automatique le VD doit permettre de superposer des périodes de 'filtration choc' ; départ immédiat et non-stop pour 12, 24, 48h d'appliquer une correction à la courbe 0 à 400% par exemple pour s'adapter aux périodes de sur-fréquentation ou vent ou.... de proposer un bouton 'baignade' qui permettrait de mettre en marche une heure histoire d’être certain d'avoir la circulation d'eau pour masser le dos :-). de reprendre la planification après un reboot HC2 quelques pistes pour l'affichage dans le VD affichage température de référence utilisée pour le calcul + durée totale de filtration du mode auto affichage température courante affichage état pompe bouton baignade bouton "CHOC +12" + affichage progression choc totale/restante bouton "annuler choc" ajustement 0 à 400% Je vais arrêter la, car c fait déjà pas mal de cas à gérer sans tomber dans une usine à gaz. voila une maquette de VD
  2. Steven

    Double-Clique Pour Confirmer

    CODER UN BOUTON FONCTIONNANT UNIQUEMENT SUR DOUBLE-CLIQUE Les boutons des modules virtuels ne permettent malheureusement pas grand chose d'autre que de cliquer dessus. Il arrive même parfois que nous cliquions sur un bouton par inadvertance. Dans la plus part des cas cela n'est pas grave mais pour certaines opérations sensibles, il serait judicieux de pouvoir valider notre clique. L'idée (soumise par @Moicphil) est de déclencher l'action uniquement lors d'un double-clique sur le bouton. Pour réaliser cela, il nous faut : Un bouton Un label Le label va nous servir à avertir l'utilisateur qu'un double-clique est nécessaire, mais il va surtout nous servir à savoir si un clique précédent a été effectuer. Au premier clique, le système affiche le message pendant un temps limité. Si pendant ce temps, l'utilisateur ré appuie sur le bouton, l'action est confirmée, sinon on retire le message et la confirmation est annulée. Voici donc le code a implémenter derrière votre bouton : -- ---------------------------- -- Ne pas toucher -- -- ---------------------------- function confirm(msg, labelId, secondes) local current = fibaro:getValue(fibaro:getSelfId(), "ui."..labelId..".value") if (current == msg) then fibaro:call(fibaro:getSelfId(), "setProperty", "ui."..labelId..".value", " ") return true else fibaro:call(fibaro:getSelfId(), "setProperty", "ui."..labelId..".value", msg) fibaro:sleep(secondes*1000) fibaro:call(fibaro:getSelfId(), "setProperty", "ui."..labelId..".value","") return fibaro:getValue(fibaro:getSelfId(), "ui."..labelId..".value") == " " end end -- ---------------------------- -- A vous de jouer --- -- ---------------------------- local message = "Ré-appuyer pour confirmer" -- le message de confirmation local label_id = "lblMessage" -- l'ID du label qui recevra le message local duree = 1 -- la durée max entre 2 clique (en seconde) if ( confirm(message, label_id, duree) ) then fibaro:log("Confirmé") -- votre code ici en cas de confirmation else fibaro:log("Annulé") -- votre code ici en cas d'annulation end Le code n'est pas si compliqué et la partie qui vous intéresse début à la ligne 21. Voilà , j'espère que cela puisse vous éviter quelque catastrophe P.S. Il y a aussi moyen d'utiliser une variable global à la place du label mais l'insertion d'une valeur dans une variable globale est trop lente pour être viable.
  3. Voici un Scène qui va vous permettre de savoir si on est le jour ou la nuit et d'avoir un décalage en minute par rapport ou jour ou a la nuit IL va nous falloir pour cette scène 2 variables globales et 1 variable globale prédéfinie Jour_Nuit (Variable prédéfinie avec comme valeur Jour ou Nuit. elle aura 2 déclenchements) SoleilLever (cette variable recevra les valeurs de la table TLever elle aura donc autant de déclenchement que de valeur dans la table TLever) SoleilCoucher (Cette variable recevra les valeurs de la table TCoucher, elle aura donc autant de déclenchement que de valeur dans la table TCoucher) Ces variables seront créées automatiquement si vous êtes en V4. Vous pouvez donnez un autre nom a chaque variable globales que les valeurs par défaut. -- Nom des Variables Globales local VGJourNuit = "Jour_Nuit" local VGLeverSoleil = "SoleilLever" local VGCoucherSoleil = "SoleilCoucher" -- Minutes de décalages par rapport au lever du soleil local TLever = {-60, -15, 30, 60, 50, 124} -- Minutes de décalages par rapport au Coucher du soleil local TCoucher = {-5, 30, 0, -30} -- Id du téléphone local IdTel = 181 Pour notre ami JoJo ainsi qu'a tout ceux qui sont en V3.60 il faudra crées les variables manuellement et désactivé ces trois lignes VerifVG(VGJourNuit, "Jour", {"Jour", "Nuit"}) VerifVG(VGLeverSoleil, 0) VerifVG(VGCoucherSoleil, 0) ----------------------------- Il faut renseigner IdTel avec l'id de votre téléphone cela va servir a vous envoyez une notification lorsque la box démarre ou lorsqu il y a modification de la scène. Une notification est aussi possible si il y a un probléme de variable globale. Le programme est optimisez pour que le sleep passe automatiquement de 1 mn à 30 mn en fonction des valeurs des tables coucher et lever Exemple d'utilisation : Scène bloc : Scène LUA je veux un déclenchement de scène (Il n'y a aucun ordre a respecter) 45 minutes avant le lever = -45 15 minutes avant le lever = -15 23 minutes apres le lever = 20 1h20 minutes apres le lever = 80 0 minutes = Jour dans la tables TLever il est donc inutile de mettre 0, il sera ajouter automatiquement a la table Je renseigne donc ma table TLever comme ceci local TLever = {-45, 20, 80, -15} Je fais de même avec la table TCoucher local TCoucher = {-5, 30, -30} Récupération des triggers dans une scène Utilisation de la variables globales Jour_Nuit comme trigger --[[ %% globals Jour_Nuit --]] local JourNuit = fibaro:getGlobalValue("Jour_Nuit") if JourNuit == "Jour" then fibaro:debug("Il fait "..JourNuit) end if JourNuit == "Nuit" then fibaro:debug("Il fait "..JourNuit) end Utilisation de ou des variables globales SoleilLever et SoleilCoucher comme trigger --[[ %% globals SoleilLever SoleilCoucher --]] local trigger = fibaro:getSourceTrigger() if (trigger['type'] == 'global') then LeverCoucher = trigger['name'] valeur = tonumber(fibaro:getGlobalValue(LeverCoucher)) print(nom, valeur) end -- le code dans ce test sera déclencher 15 mn aprés le coucher if LeverCoucher == "SoleilCoucher" and valeur == 15 then fibaro:call(7, "close") --Fermeture volet 15 mn après le coucher end -- le code dans ce test sera déclancher 30 mn avant le coucher if nom == "SoleilLever" and valeur == -30 then fibaro:call(7, "close") --Fermeture volet 30 mn avant le lever du soleil end Merci a STEVEN pour m'avoir aider a optimisez ce code Voici le code a copier dans une scène Version 3.00b --[[ %% autostart --]] -- Nom des Variables Globales local VGJourNuit = "Jour_Nuit" local VGLeverSoleil = "SoleilLever" local VGCoucherSoleil = "SoleilCoucher" -- Minutes de décalages par rapport au lever du soleil local TLever = {-60, -15, 30, 60, 50, 124} -- Minutes de décalages par rapport au Coucher du soleil local TCoucher = {-5, 30, 0, -30} -- Id du téléphone local IdTel = 181 --************ Ne rien modifier en dessous de cette ligne ************ ---------------------------------------------------------------------- -- Envoi d'un Push pour avertir que le box à démarrer ou redémarrer -- ---------------------------------------------------------------------- function EnvoiPush(Message) fibaro:debug(Message) fibaro:call(IdTel, "sendPush", Message) end -- ----------------------------------------------------------------- -- Vérification Variable Globale et création si besoin -- -- ----------------------------------------------------------------- function VerifVG(nom, valeur, choix) if (fibaro:getGlobalValue(nom) == nil) then local enum = 0 if (type(choix) ~= "nil") then enum = 1 end api.post("/globalVariables", {name=nom, isEnum=enum}) if enum == 1 then local variable = {} variable.value = tostring(valeur) variable.isEnum = false if (type(choix) ~= "nil") then variable.isEnum = true variable.enumValues = choix end api.put("/globalVariables/" .. nom, variable) end end end ---------------------------------------------------------------------- -- Mise a jour d'une variable global -- ---------------------------------------------------------------------- function UpdateVG(NomVG, Valeurs) if (fibaro:getGlobalValue(NomVG) == nil) then fibaro:debug("il faut cree la variable "..NomVG) EnvoiPush(string.format("La variable Globale %s n'existe pas ou a ete supprimer", NomVG)) fibaro:abort() -- fin du programme end fibaro:debug("Mise a jour de la Variable Globale : "..NomVG.." = "..Valeurs) fibaro:setGlobal(NomVG, Valeurs); end ---------------------------------------------------------------------- -- Vérification de l'heure et mise à jour -- -- de la variable si nécessaire -- ---------------------------------------------------------------------- function UpdateJourNuit(NomVG, heure) local valeurs = "Nuit" -- test si on est le jour ou la nuit if (heure >= leverSoleil) and (heure < coucherSoleil) then valeurs = "Jour" end fibaro:debug(string.format("Lever Soleil : %s - Coucher Soleil : %s", leverSoleil, coucherSoleil)) UpdateVG(NomVG, valeurs) -- mise a jour de la VG Jour_Nuit end ---------------------------------------------------------------------- -- Compare les tables Lever et coucher du soleil -- -- avec sunrisehour et sunsethour -- ---------------------------------------------------------------------- function LeverCoucher(NomVG, TableNom, SunRiseSet, JourNuit) for index, v in ipairs(TableNom) do if (os.date("%H:%M", os.time()+v*-60)) == SunRiseSet then UpdateVG(NomVG, v) if v == 0 then fibaro:debug("il fait : "..JourNuit) UpdateVG(VGJourNuit, JourNuit) end end end end ---------------------------------------------------------------------- -- Conversion Date format texte en format Date -- ---------------------------------------------------------------------- function ConvertionDate(NomDate) -- on extrait l'heure et minute (%d+) est un digit local heure, minute = string.match(NomDate, "(%d+):(%d+)") -- On récupère l'heure et date actuelle sous forme de tableau local TableDate = os.date("*t") -- On modifie l'heure et les minutes TableDate.hour = heure TableDate.min = minute -- Nous pouvons maintenant exploiter "MonHeure" comme une vrai date local MonHeure = os.time(TableDate) return (MonHeure) end ---------------------------------------------------------------------------- -- Calcul la valeur du Sleep en fonction des Max et Mini -- -- des Tables Lever et Coucher -- ---------------------------------------------------------------------------- function calculPause(j, heure, minilever, maxilever, minicoucher, maxicoucher) fibaro:debug("Heure Actuelle : "..heure) -- mini et max lever local heurelever = ConvertionDate(leverSoleil) local heureleverMini = (os.date("%X", heurelever+(minilever*60))) local heureleverMaxi = (os.date("%X", heurelever+(maxilever*60))) fibaro:debug("heure Lever Soleil Mini : "..heureleverMini.." - Maxi : "..heureleverMaxi) -- mini et max coucher local heurecoucher = ConvertionDate(coucherSoleil) local heurecoucherMini = (os.date("%X", heurecoucher+(minicoucher*60))) local heurecoucherMaxi = (os.date("%X", heurecoucher+(maxicoucher*60))) fibaro:debug("heure Coucher Soleil Mini : "..heurecoucherMini.." - Maxi : "..heurecoucherMaxi) if heure >= heureleverMini and heure < heureleverMaxi or heure >= heurecoucherMini and heure < heurecoucherMaxi then j=1 end return (j) end -- =================================================================== -- == Nous avons fini la préparation de notre code == -- == Nous pouvons Exécuter le programme == -- == Script réaliser par MPRINFO Version 3.00B == -- == Grand Merci à STEVEN pour son aide == -- =================================================================== ---------------------------------------------------------------------- -- Envoi d'un Push pour donner la date et l'heure de démarrage -- ---------------------------------------------------------------------- EnvoiPush(string.format("La box a démarré le %s a %s", os.date("%d/%m/%Y"), os.date("%R"))) ---------------------------------------------------------------------- -- Contrôle si 1 Scène et déjà en cours -- ---------------------------------------------------------------------- local NbreScene = fibaro:countScenes() if NbreScene ~= 1 then; fibaro:debug("Il y a déjà une instance en cours... ") fibaro:abort(); end ---------------------------------------------------------------------- -- Vérification si les variables globales existe -- -- et Création ou Modification si Besoin -- ---------------------------------------------------------------------- VerifVG(VGJourNuit, "Jour", {"Jour", "Nuit"}) VerifVG(VGLeverSoleil, 0) VerifVG(VGCoucherSoleil, 0) ---------------------------------------------------------------------- -- Mise a jour de la variable VG Jour_Nuit au Démarrage de la Box -- -- Ou lors de la sauvegarde de la scène -- ---------------------------------------------------------------------- leverSoleil = fibaro:getValue(1, "sunriseHour") coucherSoleil = fibaro:getValue(1, "sunsetHour") UpdateJourNuit(VGJourNuit, os.date("%H:%M", os.time())) --------------------------------------------------------------------- -- Trie des Tables et récupération des valeurs min et maximum -- --------------------------------------------------------------------- -- Traitement de la Table TLever table.insert(TLever, 1, 0) -- ajout de 0 mn dans la table table.sort(TLever) local MiniLever = ((TLever[1]-30)) local MaxiLever = ((TLever[#TLever]+1)) -- Traitement de la Table TChoucher table.insert(TCoucher, 1, 0) -- ajout de 0 mn dans la table table.sort(TCoucher) local MiniCoucher = ((TCoucher[1]-30)) local MaxiCoucher = ((TCoucher[#TCoucher]+1)) --------------------------------------------------------------------- -- Test toute les minutes pour savoir si c'est jour ou nuit -- --------------------------------------------------------------------- while true do local j = 30 local osHeure = os.date("%H:%M", os.time()) leverSoleil = fibaro:getValue(1, "sunriseHour") coucherSoleil = fibaro:getValue(1, "sunsetHour") LeverCoucher(VGLeverSoleil, TLever, leverSoleil, "Jour") LeverCoucher(VGCoucherSoleil, TCoucher, coucherSoleil, "Nuit") j = calculPause(j, osHeure, MiniLever, MaxiLever, MiniCoucher, MaxiCoucher) fibaro:debug(string.format("Valeur du Sleep %s mn",j)) fibaro:sleep(j*60*1000); -- Pause en fonction de la valeur de J end A ceux qui vont utiliser cette scène, Merci de me faire un retour sur ce code...
  4. Pluviométrie Avec WeatherUnderground Bonjour, Sur une idée originale de Steven, qui remonte les données d'un pluviomètre Netatmo et récupère les previsions depuis le site de WU, j'ai crée ce VD qui permet de s'affranchir de l'achat d'un pluviomètre et de faire appel uniquement à WU pour récupérer les précipitations (de la dernière heure, du jour, d'hier, des 5 derniers jours et des 10 derniers jours) d'une station WU proche de chez vous; Suite à ca on fait un rapide calcul (à affiner selon vos besoins) pour mettre à jour une variable globale. (credit Steven aussi - je n'ai pas encore affiner ce calcul avec les datas que je remonte - ca sera une V2) Cette variable sert ensuite chez moi à déclencher l'arrosage automatique. HC2 en V4 (et 3.6 après le test de Jojo) 1ère étape - Creation des clefs WU à l'adresse ici Pour crée un compte : http://www.wundergro...pi/d/login.html Pour trouver sa "station ID" : http://www.wundergro...dCountry=France La création du compte va vous permettre d'obtenir une "cle api" Et la recherche de la station la plus proche de chez vous, une station ID (attention à bien choisir une station qui mesure à les precipitations .. ;-) Important Les clés gratuites permettent 500 appels par jour et 10appels par minutes. Dans le VD vous avez 4 boutons - Today qui fait 1 appel - Last Days, qui fait 10 appels - Next 2 days, qui fait 1 appel il faut donc faire attention à vos clicks :-) si vous dépasser la limite, c'est le carton jaune, au bout de 3 carton jaune, c'est le rouge et la clé est HS. (Perso ce que j'ai fait c'est créer une clé pour les 10jours. et une autre pour les 2 autres boutons, et j'utilise GEA pour cliquer à intervalle régulier sur les boutons, sans dépasser les 500 appels jours / clef.) -- Arrosage GEA.add(true, 10*60, "", {{"VirtualDevice", id["CALCUL_ARROSAGE"], 2},{"Repeat"}}) -- Historique Pluie du Jour et derniere heure GEA.add(true, 30, "", {{"Time", "02:06", "02:07"},{"VirtualDevice", id["CALCUL_ARROSAGE"], 5}}) -- Historique Pluie jusqu'à 10jours GEA.add(true, 10*60, "", {{"VirtualDevice", id["CALCUL_ARROSAGE"], 9},{"Repeat"}}) -- Prévisions à 2 jours ce qui donne 300 appels par jour et max 10appels /mn - donc ok pour 1clef, sauf si l'appel 10jours passe la meme minutes qu'un autre appel ... Pour ceux qui n'ont pas GEA, voici ce que vous pouvez mettre dans le main loop (j'ai pas testé donc merci pour vos retours si ça fonctionne pas) while true do local Var_Heure = os.date("%H:%M") local Var_Min = os.date("%M") --fibaro:debug("heure OS : " ..Var_Heure) if Var_Heure == "02:06" then fibaro:call(fibaro:getSelfId(), "pressButton", "5") fibaro:debug("heure OS : " ..Var_Heure .."Historique des derniers jours récupéré") end if Var_Min =="00" or Var_Min == "15" or Var_Min == "30" or Var_Min == "45" then fibaro:call(fibaro:getSelfId(), "pressButton", "2") fibaro:debug("heure OS : " ..Var_Heure .."Historique du jour récupéré") fibaro:call(fibaro:getSelfId(), "pressButton", "9") fibaro:debug("heure OS : " ..Var_Heure .."Prévisions récupérées") end fibaro:sleep(60*1000) -- sleep 1 min end 2eme étape - Importer le VD - Modifier la clé (ou les clefs) API et la Station ID dans tous les boutons (sauf calcul) - Modifier l'id de votre smartphone dans le bouton calcul arrosage - Modifier les ID de vos icones dans la bouton calcul arrosage 3eme étape - Créer une variable "Arrosage" avec 3 valeurs Non, Leger, Important J'utilise les icônes de Couillerot merci à lui. Merci. Mon 1er VD partagé sur le forum. En remerciement pour tout ce que je prends/deja pris et ce que j'apprends ! V.1.0 V.1.1: optimisation sur conseil de jojo V.1.2: integration des icônes en fonction de l'arrosage nécessaire (toujours sur idée de jojo) V.1.3: meilleure gestion des appels et 1clé WU peut suffire V.1.4: fine tuning V.1.5: optimisation des appels historiques sur 1 bouton (merci jojo) -- 15 Mai 2015 -- V2.1 : ici Calcul_Arrosage V1.5.vfib
  5. Barelle

    VD UPS

    Hello, Comme vous le savez, nos matériels électroniques n’apprécient pas du tout les coupures électriques. Pour cela, il est plus que recommandé d’utiliser un onduleur (ou UPS, "Uninterruptible Power Supply")… Le VD que je vous propose ici permet l’interrogation du serveur UPS résidant sur un NAS Synology (auquel l’onduleur est connecté par un port USB). Il met à jour une variable globale (appelée UpsStatus par défaut) avec les valeurs "power-line" ou "battery" selon que l’onduleur est sur secteur ou sur batterie. Cette variable globale permet le lancement de la scène ci-après qui : - lors d’un passage sur batterie, après le délai "delayBeforePowerOff" réalisera l’arrêt de la HC2 ; - lors du retour de l’alimentation, appuiera sur le bouton "WOL" du VD. Là aussi, le réveil se fera après un délai "delayBeforeWakeUp". Ces délais ont pour objet de s’affranchir de retours temporaires de tension. --[[ %% properties %% events %% globals UpsStatus --]] local globalVarName = "UpsStatus"; -- values "power-line" or "battery" local wolVdId = "337"; local wolVdBtnId = "11"; local delayBeforePowerOff = 5; -- minutes local delayBeforeWakeUp = 5; -- minutes local debug = true; function trace(text, color) color = color or "white"; if debug then fibaro:debug("<font color='"..color.."'>"..text.."</font>"); end end -- trace function tracerr(text, color) color = color or "red"; fibaro:debug("<font color='red'>ERROR! </font>".."<font color='"..color.."'>"..text.."</font>"); end -- tracerr function wakeOnLan() fibaro:call(wolVdId, "pressButton", wolVdBtnId); end -- wakeOnLan local sourceTrigger = fibaro:getSourceTrigger(); trace("sourceTrigger[type] = " .. sourceTrigger["type"], "deepskyblue"); if (sourceTrigger["type"] == "global") then if (sourceTrigger["name"] ~= globalVarName) then tracerr("unknown global "..sourceTrigger["name"].." exiting"); fibaro:abort(); end elseif (sourceTrigger["type"] == 'other') then trace("Scene triggered manually", "lightgreen"); -- inform user local upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= nil) then trace(globalVarName.." = "..upsStatus, "lightgreen"); fibaro:abort(); end else tracerr("unexpected trigger type ".. sourceTrigger["type"], "orange"); fibaro:abort(); end if (fibaro:countScenes() > 1) then trace("Script already running, exiting.", "green"); return; end local upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus == nil) then tracerr("global "..globalVarName.." = nil"); fibaro:abort(); end if (upsStatus == "power-line") then local i = 0; for i = 1, (delayBeforeWakeUp * 6) do -- check every 10 seconds during delayBeforeWakeUp minutes fibaro:sleep(10 * 1000); -- ten seconds upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= "power-line") then trace("Still on battery, aborting", "orange"); fibaro:abort(); -- not stable end end -- Time to wake up devices trace("Waking up devices", "lightgreen"); wakeOnLan(); elseif (upsStatus == "battery") then local i = 0; for i = 1, (delayBeforePowerOff * 6) do -- check every 10 seconds during delayBeforePowerOff minutes fibaro:sleep(10*1000); -- ten seconds upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= "battery") then trace("Power is back, shut down aborted", "orange"); fibaro:abort(); end end -- shutdown HC2 gracefully trace("shutting down", "lightgreen"); fibaro:sleep(10*1000); HomeCenter.SystemService.shutdown(); else tracerr("global "..globalVarName.." unknown value: "..upsStatus); end Installation du VD : - Importer le VD, - Renseigner l’adresse IP du NAS connecté à l’onduleur, le port TCP 3493 est optionnel. - Les username et password présents dans le code du bouton Update fonctionnent pour un Synology. - Dans le code du bouton WOL, vous devrez préciser les adresses MAC des matériels que vous souhaitez réveiller. Il va de soi qu’ils devront être paramétrés pour accepter les "magic packets" afin d’être réveillés (pour les PC vérifier les paramètres de la carte réseau). - Pour les Nas Synology, il faut activer le WOL : "Panneau de configuration", "Matériel et alimentation", onglet "Général", cocher "Activer WOL sur le réseau local x". - Et ne pas oublier d’activer le serveur réseau UPS : "Panneau de configuration", "Matériel et alimentation", onglet "UPS", cocher "Activer la prise en "charge UPS" et "Activer le serveur réseau UPS"). - Enfin bien sûr, trouver une jolie icône pour les boutons du VD. Installation de la scène : - Préciser l’id du VD réalisant le WOL dans "wolVdId". - et le numéro du bouton à appuyer "wolVdBtnId". Pour ceux qui veulent personnaliser le VD, le code du bouton "Update" contient, à la fin, une description des principaux champs retournés par les serveurs UPS, Tous ne sont pas implémentés par Synology ou mon onduleur. Configuration utilisée pour les tests : - HC2 : 4.153 Beta - Onduleur : Eaton Ellipse PRO 1200 - NAS : Synology DS1010+ with DSM 5.2-5967 Update 6 Joyeux réveillon et bonne année à tous… UPS.vfib
  6. Steven

    Pluviométrie Avec Netatmo

    PLUVIOMETRIE (ET ARROSAGE) AVEC NETATMO firmware 4.x seulement Partie 1 : récupérer l'historique Netatmo est une station météo sur laquelle vous pouvez brancher un "pluviomètre" de la même marque. Afin d'exploiter les données de ce pluviomètre et vous pouvez utiliser l'application Netatmo ou son site web. Vous pouvez aussi installer le plugin Netatmo fourni par Fibaro. Ce dernier vous affichera uniquement les données à l'instant précis ou vous être entrain de le regarder. Nous, nous voulons allez plus loin, nous voulons connaitre les quantités de pluie ayant eu lieu depuis : 1 jour, 1 semaine, 1 mois, cela dans l'optique de pouvoir gérer correctement notre arrosage. Pour ce faire, il existe un grand nombre de script PHP, Google Script qui permet de gérer cela .. mais ... depuis la v4.x, Fibaro nous fait bénéficier de la librairie net.httpClient dans une scène et cette librairie nous permet de récupérer des données via HTTPS, ce qui auparavant n'était pas possible depuis notre HC2. Alors vu que nous avons, aujourd'hui, tout le nécessaire pour attaquer notre Netatmo directement depuis notre HC2, pourquoi s'en priver Les données recueillies par votre Netatmo sont mis à diposition via des API que vous pouvez interroger quand bon vous semble à la seul condition d'avoir un compte Développeur Netatmo (ne vous inquiéter pas, vous n'aurez pas beson de développer, ni de répondre à des questions étranges). Pour vous inscrire, c'est donc ici : https://auth.netatmo.com/fr-FR/access/signup Suite à votre enregistrement, vous allez obtenir : un id (exemple : 45b1931d19665803515b571c) un code secret (exemple : lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4) Ces informations + votre login et mot de passe vont permettre d'accéder à vos informations. Voici donc le script nécessaire, à vous de l'importer dans une nouvelle scène et de modifier les 4 premières lignes. local n_client_id = "45b1931d19665803515b571c" local n_client_secret = "lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4" local n_username = "______________@_____.com" local n_password = "password" local hc2_module_virtuel = 139 -- le module virtuel "Pluie" local debug = true -- affiche ou non les message dans la console local long_lat_adjust = 0.1 -- ajustement de la distance pour trouvé un pluviomètre local version = 2.0 -- ------------------------------------------------------------------------ -- NE PAS TOUCHER -- ------------------------------------------------------------------------ local force_use_rain_public = false local loc = api.get("/settings/location") local lat_ne = loc.latitude + long_lat_adjust local lon_ne = loc.longitude + long_lat_adjust local lat_sw = loc.latitude - long_lat_adjust local lon_sw = loc.longitude - long_lat_adjust local token = "" local int_id = "" local ext_id = "" local ext_bat = 0 local rain_id = "" local rain_bat = 0 local temperature_interieure = -1000 local temperature_exterieure = -1000 local co2 = -1000 local humidite_interne = -1000 local humidite_externe = -1000 local pression = -1000 local bruit = -1000 local rains = {hour = -1000, day = -1000, week = -1000, month = -1000} -- ------------------------------------------------------------------------ -- Exécuté après chaque requète HTTP -- ------------------------------------------------------------------------ function afterHttpRequest() if (temperature_interieure > -1000) then end if (temperature_exterieure > -1000) then end if (co2 > -1000) then end if (humidite_interne > -1000) then end if (humidite_externe > -1000) then end if (pression > -1000) then end if (bruit > -1000) then end if (rains["hour"] > -1000) then if (rains["hour"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", " "..rains["hour"]) end end if (rains["day"] > -1000) then if (rains["day"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", " "..rains["day"]) end end if (rains["week"] > -1000) then if (rains["week"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", " "..rains["week"]) end end if (rains["month"] > -1000) then if (rains["month"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", " "..rains["month"]) end end end -- ------------------------------------------------------------------------ -- Affichage dans la console -- ------------------------------------------------------------------------ function log(message, force) force = force or false if (debug or force) then print(__convertToString(message)) end end -- ------------------------------------------------------------------------ -- Retourne le niveau de batterie en pourcent -- ------------------------------------------------------------------------ function calcBat(bat, ext) local max = 6000 local min = 4200 if (ext) then max = 6000 min = 3600 end if (bat > max) then bat = max end return math.floor(bat * 100 / max) end -- ------------------------------------------------------------------------ -- Arrondi -- ------------------------------------------------------------------------ local function roundToNthDecimal(num, n) local mult = 10^(n or 0) return math.floor(num * mult + 0.5) / mult end -- ------------------------------------------------------------------------ -- Interrogation de l'API -- ------------------------------------------------------------------------ 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 }, success = function(response) func(json.decode(response.data)) afterHttpRequest() end, error = function(response) log(" ERROR !!! " .. url, true) end, }) end -- ------------------------------------------------------------------------ -- Mesures de l'unité interne -- ------------------------------------------------------------------------ function getMesuresInt() getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&scale=max&type=Temperature,CO2,Humidity,Pressure,Noise&date_end=last", function(data) log("----------========== Module intérieur ==========----------") temperature_interieure = data.body[1].value[1][1] co2 = data.body[1].value[1][2] humidite_interne = data.body[1].value[1][3] pression = data.body[1].value[1][4] bruit = data.body[1].value[1][5] log("temperature_interieure = " .. temperature_interieure) log("co2 = " .. co2) log("humidite_interne = " .. humidite_interne) log("pression = " .. pression) log("bruit = " .. bruit) end ) end -- ------------------------------------------------------------------------ -- Mesure de l'unité externe -- ------------------------------------------------------------------------ function getMesuresExt() getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..ext_id.."&scale=max&type=Temperature,Humidity&date_end=last", function(data) log("----------========== Module extérieur ==========----------") temperature_exterieure = data.body[1].value[1][1] humidite_externe = data.body[1].value[1][2] log("temperature_exterieure = " .. temperature_exterieure) log("humidite_externe = " .. humidite_externe) end ) end -- ------------------------------------------------------------------------ -- Obtention des informations sur un pluviomètre proche -- ------------------------------------------------------------------------ function getRainNear() getResponseData("https://api.netatmo.net/api/getpublicdata","access_token="..token .. "&lat_ne="..lat_ne.."&lon_ne="..lon_ne.."&lat_sw="..lat_sw.."&lon_sw="..lon_sw, function(data) --log(data) rains["week"] = -1 rains["month"] = -1 rains["hour"] = -1 rains["day"] = -1 log("----------========== D e v i c e s =========----------") for _, v in pairs(data.body) do for l, w in pairs(v.measures) do if (type(w.rain_24h) ~= "nil") then rains["day"] = w.rain_24h rains["hour"] = w.rain_60min end end end if (rains["day"] == -1000) then log("Impossible de trouver un pluviomètre à proximité, augmentez [long_lat_adjust]", true) else log("Pluie jour : " .. rains["day"]) log("Pluie heure : " .. rains["hour"]) end end ) end -- ------------------------------------------------------------------------ -- Mesure du détecteur de pluie historique -- ------------------------------------------------------------------------ function getMesuresRain(duree, variable) local now = os.time(); getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..rain_id.."&scale=1hour&type=sum_rain&real_time=true&date_begin="..os.date("!%c", (now - duree)), function(data) log("----------========== Pluie histo ==========----------") local cumul = 0 for k, v in pairs(data.body) do for l, w in pairs(v.value) do cumul = cumul + w[1] end end cumul = roundToNthDecimal(cumul, 2) rains[variable] = cumul log("rain["..variable.."] = " .. rains[variable]) end ) end -- ------------------------------------------------------------------------ -- Obtention des informations sur les devices -- ------------------------------------------------------------------------ function getDevices() getResponseData("https://api.netatmo.net/api/devicelist","access_token="..token, function(data) log("----------========== D e v i c e s =========----------") for _, v in pairs(data.body.modules) do if (v.data_type[1] == "Rain") then rain_id = v._id rain_bat = calcBat(v.battery_vp, true) else ext_id = v._id ext_bat = calcBat(v.battery_vp, true) end end int_id = data.body.devices[1]._id getMesuresInt() getMesuresExt() if (rain_id ~= "" and not force_use_rain_public) then getMesuresRain(60 * 60, "hour") getMesuresRain(60 * 60 * 24, "day") getMesuresRain(60 * 60 * 24 * 7, "week") getMesuresRain(60 * 60 * 24 * 30, "month") else getRainNear() end end ) end -- ------------------------------------------------------------------------ -- Authentification -- ------------------------------------------------------------------------ function auth(nextFunction) local request_body = "grant_type=password&client_id=" .. n_client_id .. "&client_secret=" .. n_client_secret .. "&username=" .. n_username .. "&password=" .. n_password .. "&scope=read_station" getResponseData("https://api.netatmo.net/oauth2/token", request_body, function(data) token = data.access_token log(token) nextFunction() end ) end auth(getDevices) log("Last request : " .. os.date("%x - %X"), true) si vous avez l'âme d'un développeur ou d'un aventurier, la méthode à modifier est afterHttpRequest() sinon, rendez-vous au post suivant. P.S. Merci à @PITP2 pour son support. Edit : nouvelle version du script. Si ce dernier détecte que vous n'avez pas de pluviomètre, il va rechercher un pluviomètre à proximité de chez vous (uniquement les relevés de la dernière heure et jour). La distance de recherche peux être adaptée en ajustant la variable long_lat_adjust (0.1 par défaut). Il s'agit du cercle de recherche en latitude/longitude autour de chez vous.
  7. HANSOLO

    Jour Chômé

    V2 du 27/06/2014 grandement amélioré par STEVEN Nouveautés de la V2: - Calcul si le jour en cours et jour +1 est chômé ou pas - Choix des jours fériés France ou Suisse - Ce qui change par rapport à la V1: ajout d'un label dans le module virtuel et ajout d'une variable globale JourChomeJ1, pour lancer le calcul depuis GEA ou SCHEDULER bouton 3 au lieu de 2 pour la version précédente. Objectif: calculer si le jour en cours est chômé (WE ou férié) ou pas et stocker le résultat dans une variable globale, le tout sans dépendre d'un agenda externe à la HC2 et de script intermédiaire. Il s'agit d'une légère adaptation du code pour la VERA LITE de josDBlog http://gurau-audibert.hd.free.fr/josdblog/2014/01/lua-vacances-jours-chomes-et-jours-feries/ 1er étape, dans le panneau des variables, créer deux variables globale prédéfinie JourChome JourChomeJ1 avec les valeurs prédéfinies OUI NON. 2 iém étape, créer un module virtuel avec deux labels et un bouton: Le détail: Et ci-dessous la code à coller dans le bouton du module virtuel: -- Retourne OUI si le jour courant et J+1 est un jour chômé (WE ou férié) -- Adapté de http://gurau-audibert.hd.free.fr/josdblog/2014/01/lua-vacances-jours-chomes-et-jours-feries/ -- Pour la HC2 par Hansolo -- V1 26/06/2014 Initié par HANSOLO -- V2 27/06/2014 Amélioré par STEVEN, gestion des JS SUISSE et calcul J et J+1 local france = true local suisse = false local geneve = false -- Retourne le jour de la semaine en clair function josdGetJourSemaine(jour) --fibaro:debug ("jour: ") josdGetJourSemaineTab={[0]="dimanche",[1]="lundi",[2]="mardi",[3]="mercredi",[4]="jeudi",[5]="vendredi",[6]="samedi"} return josdGetJourSemaineTab[tonumber(jour)] end -- Retourne le jour de Pâques au format epoch -- annee : année (Integer) dont on désire connaître le jour de Pâques (ex : 2014) function josdGetJourPaques(annee) local a=math.floor(annee/100); local b=math.fmod(annee,100); local c=math.floor((3*(a+25))/4); local d=math.fmod((3*(a+25)),4); local e=math.floor((8*(a+11))/25); local f=math.fmod((5*a+,19); local g=math.fmod((19*f+c-e),30); local h=math.floor((f+11*g)/319); local j=math.floor((60*(5-d)+b)/4); local k=math.fmod((60*(5-d)+,4); local m=math.fmod((2*j-k-g+h),7); local n=math.floor((g-h+m+114)/31); local p=math.fmod((g-h+m+114),31); local jour=p+1; local mois=n; josdGetJourPaquesAnnee=annee; josdGetJourPaquesEpochPaque=os.time{year=annee,month=mois,day=jour,hour=12,min=0}; return josdGetJourPaquesEpochPaque; end -- Retourne true si le jour courant est un jour férié function josdJourFerie(time) local today=os.date("%m-%d", time); local annee=tonumber(os.date("%Y", time)); -- Dates fixes josdJourFerieTab = {} local epochPaques=josdGetJourPaques(annee); if (france) then josdJourFerieTab["01-01"] = true; -- 1er janvier josdJourFerieTab["05-01"] = true; -- Fête du travail josdJourFerieTab["05-08"] = true; -- Victoire des alliés josdJourFerieTab["07-14"] = true; -- Fête nationale josdJourFerieTab["08-15"] = true; -- Assomption josdJourFerieTab["11-01"] = true; -- Toussaint josdJourFerieTab["11-11"] = true; -- Armistice josdJourFerieTab["12-25"] = true; -- Noà«l -- Dates variables josdJourFerieTab[os.date("%m-%d",epochPaques)] = true; -- Pâques josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60)] = true; -- Lundi de Pâques = Pâques + 1 jour josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*39)] = true; -- Ascension = Pâques + 39 jours josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*50)] = true; -- Pentecôte = Ascension + 50 jours end if (suisse) then josdJourFerieTab["01-01"] = true; -- 1er janvier josdJourFerieTab["08-01"] = true; -- Fête national josdJourFerieTab["12-25"] = true; -- Noà«l -- Dates variables if (geneve) then josdJourFerieTab[jeuneGenevois(time)] = true; -- jeunes genevois else josdJourFerieTab[jeuneFederal(time)] = true; -- jeunes genevois end josdJourFerieTab[os.date("%m-%d", epochPaques)] = true; -- Pâques josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60)] = true; -- Lundi de Pâques = Pâques + 1 jour josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60*39)] = true; -- Ascension = Pâques + 39 jours josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60*50)] = true; -- Pentecôte = Ascension + 50 jours josdJourFerieTab[os.date("%m-%d", epochPaques-48*60*60)] = true; -- Vendredi-saint = Pâques - 2 jour end return josdJourFerieTab[today]; -- (nldr : Both nil and false make a condition false) end -- Calcul le jeudi qui suit le 1er dimanche de septembre function jeuneGenevois(time) local jour = 1 local annee = tonumber(os.date("%Y", time)) while (os.date("%A", os.time{year=annee, month=9, day=jour}) ~= "Sunday") do jour = jour + 1 end return os.date("%m-%d", os.time{year=annee, month=9, day=(jour+4)}) end -- Calcul le lundi qui suit le 3ème dimanche de septembre function jeuneFederal(time) local jour = 1 local annee = tonumber(os.date("%Y", time)) while (os.date("%A", os.time{year=annee, month=9, day=jour}) ~= "Sunday") do jour = jour + 1 end return os.date("%m-%d", os.time{year=annee, month=9, day=(jour+15)}) end -- Affiche le résultat function display(jour, result, label, variable, time) selfId = fibaro:getSelfId() fibaro:debug ("Jour chomé: " .. result) -- Mise à jour de la variable globale if (variable) then fibaro:setGlobal(variable, result) end -- Mise à jour du label du module virtuel fibaro:call(selfId,"setProperty","ui."..label..".value", jour .. " " .. os.date("%d.%m.%Y ",time).." Jour chomé: ".. result) end -- Lancement du calcul function doCalculate(time, label, variable) local jour = josdGetJourSemaine(os.date("%w", time)) josdJourChomeReturn = (jour=="samedi" or jour=="dimanche" or josdJourFerie(time)) if josdJourChomeReturn then display(jour, "OUI", label, variable, time) else display(jour, "NON", label, variable, time) end end doCalculate(os.time(), "Label1", "JourChome") doCalculate(os.time()+24*60*60, "Label2", "JourChomeJ1") J’exécute le code tous les jours à 00H15 depuis le Scheduler (90 étant l'ID de mon module virtuel et 3 la position du bouton) ce qui évite d'utiliser le main loop du module virtuelle et d'éventuels problèmes. luaDaySchedule:add("00:15","90", 3 , "pressButton",{"All"},true) La même chose depuis GEA. GEA.add({"Global", "", ""}, 30, "", {{"VirtualDevice", 90, 3},{"Time", "00:00", "00:01"}}) Pour choisir les jours fériés France ou Suisse (au début du code) local france = oui local suisse = non local geneve = non Merci à STEVEN pour les améliorations. Voilà un truc tout simple que j'utilise pour gérer mes volets Correction du 13/07/2014, utiliser true ou false pour la sélection des calendriers des jours fériés local france = true local suisse = false local geneve = false Correction du 14/04/2015, calcul du jeudi de l’ascension erroné Correction du 03/05/2015, calcul du jeudi de l'ascension dans la partie Suisse Correction du 25/05/2015, calcul du lundi de pentcôte
  8. Tout est dans le titre. Il s'agit d'un simple device virtuel permettant de rebooter ou arreter un serveur synology. L'idée est inspirée de la solution de Labomatik pour QNAP La solution est tres tres largement inspirée du module virtuel de lazer permettant de piloter la surveillance station ... effectivement, je n'ai pas inventé grand chose. Toute la mécanique d'authentification est issue du dev de Lazer (que je remercie au passage). Les fonctions que l'on exploite ici ne sont pas officiellement mise à dispo par l'API Synology, mais un peu de reverse engeneering permet de retrouver ce qui est fait par l'interface web du synology. La configuration est tres simple : - Paramétrer l'adresse IP et le port du device virtuel avec l'adresse ip et le port du synology ==> Il doit s'agir d'un port HTTP. La solution ne supporte pas l'HTTPS. Dans chaque bouton, remplacer les variables par un login / password existant sur votre synology. Attention : Il doit s'agir d'un utilisateur ayant des droits admin Ajouté au virtuel device de Lazer, nous voilà aussi bien équipé que les utilisateurs QNAP. Plus de jaloux! Une remarque pour ceux qui souhaitent égallement redémarrer leur synology via la HC2 : Tous les synology ne supportent pas le Wake On Lan. Plus d'info : https://www.synology.com/fr-fr/knowledgebase/faq/437 Synology.vfib Icone pour le device virtuel :
  9. sebcbien

    Modes Éclairage Auto/manuel Waf

    Bonjour, Petit partage, un VD et quelques lignes GEA pour activer/désactiver l'éclairage automatique chez moi. J'avais déjà implémenté la possibilité d'activer un mode "manuel" via un VD et 3 boutons (Automatique / Manuel / Manuel pendant 3H) Ce mode manuel était utilisé dans GEA de la manière suivante: local estHouse_Manuel = {"Global", "House_Mode", "Manual"} local estNotHouse_Manuel = {"Global", "House_Mode", "Auto|Scheduler"} GEA.add({{"Value", id2["SAM_MVT"],1},estNotHouse_Manuel}, -1, "",{{"turnOn", id2["SALLE_A_MANGER"]}}) Problème, pour activer ce mode il fallait sortir le téléphone de sa poche, pas WAF du tout et pas pratique (mon mantra en domotique: si t'a besoin de ton téléphone pour gérer ta domotique -> FAIL) Voici la solution mà»rement réfléchie: - Un interrupteur mural (ils ont l'avantage de ne pas se perdre et d'être proches ) - Un Virtual Device qui sert aussi de Variable Globale - GEA - TTS pour le feedback J'ai donc activé le paramètre 41 (Scène activation sur un FGD) et j'utilise un long press sur S2 pour basculer du mode AUTO en Manuel et vice-versa Dans GEA, je détecte cet appui long et je clique sur le bouton correspondant du VD GEA: 1894 sceneActivation 2139 ui.ModeRez.value local estLumRez_Auto = {"Label", id2["MODES_AUTO_MANUEL"], "ModeRez", "Automatique"} local estLum1er_Auto = {"Label", id2["MODES_AUTO_MANUEL"], "Mode1er", "Automatique"} local estLumGarage_Auto = {"Label", id2["MODES_AUTO_MANUEL"], "ModeGarage", "Automatique"} ----------- GESTION MODES AUTO/MANU ----------- -- Bascule mode éclairage actuel GEA.add({{"SceneActivation", id2["POUSSOIRS_HAUT"], 12}}, -1, "Switch changing Rez Auto/Manuel Mode at #time#",{{"VirtualDevice", id2["MODES_AUTO_MANUEL"], 5}}) --Annonce TTS du Mode sauf si en passage en mode Away ou Night_All_Off GEA.add({{"Label", id2["MODES_AUTO_MANUEL"], "ModeRez", ""},estNotAwayOrNigh_All_Off}, -1, "Eclairage Rez Set to Mode: #value# at #time#", {{"Inverse"},{"Label", id2["SONOS_SAY_IT"], "Message", "éclairage ré en mode #value#."},TTS_Default}) Exemple d'utilisation: - Si un soir on veut faire un jeu de nuit avec les enfants, un simple appuy sur l'interrupteur va annoncer dans les SONOS que le mode automatique à été désactivé et plus aucune lampe ne s'allumera automatiquement. - Si mon frère passe faire un baby sitting et veut regarder son film dans le noir, il peut activer le mode lui même. - Si un matin on veut profiter de la lumière du lever de soleil sans lampes Exemple de ligne GEA qui n'allume les lampes que si le mode est en auto: GEA.add({{"Value", id2["SAM_MVT"],1},estLumRez_Auto }, -1, "",{{"turnOn", id2["SALLE_A_MANGER"]}}) A chaque fois que l'alarme est mise ou que le mode nuit est activé, GEA me remet tout en automatique: ------------ WHEN AT HOME DO------------------- GEA.add(estAt_Home, -1, "", { estLumRez_Auto, estLum1er_Auto, estLumGarage_Auto }) A partir d'un autre VD, j'ai 3 boutons - Forcer tout en automatique - Manuel - Manuel pour une durée de 3H puis retour en mode automatique Bouton tout Manuel: local selfId = fibaro:getSelfId() local NewState = "Manuel" local id2 = { --Maison (Global) MODES_AUTO_MANUEL = 2139, } fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeRez.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.Mode1er.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeGarage.value", NewState); fibaro:call(selfId, "setProperty", "ui.HouseMode.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.LastChange.value", "Tout "..NewState.." à "..os.date("%H:%M")); fibaro:debug(os.date("%a %d/%m", os.time()).." Set all modes to "..NewState); Bouton tout Auto: local selfId = fibaro:getSelfId() local NewState = "Automatique" local id2 = { --Maison (Global) MODES_AUTO_MANUEL = 2139, } fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeRez.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.Mode1er.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeGarage.value", NewState); fibaro:call(selfId, "setProperty", "ui.HouseMode.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.LastChange.value", "Tout "..NewState.." à "..os.date("%H:%M")); fibaro:debug(os.date("%a %d/%m", os.time()).." Set all modes to "..NewState); Bouton manuel pour une durée de 3H (puis retour en mode automatique si tout est toujours en manuel, donc si personne n'a appuyé sur le bouton): local selfId = fibaro:getSelfId() local NewState = "Manuel" local id2 = { --Maison (Global) MODES_AUTO_MANUEL = 2139, } fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeRez.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.Mode1er.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeGarage.value", NewState); fibaro:call(selfId, "setProperty", "ui.HouseMode.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.LastChange.value", "Tout "..NewState.." pour 3H à "..os.date("%H:%M")); fibaro:debug(os.date("%a %d/%m", os.time()).." Set all modes to "..NewState.." and wait 3H"); -- sleep 3H: --fibaro:sleep(10*1000) fibaro:sleep(60*60*1000) fibaro:debug(os.date("%a %d/%m", os.time()).." 1H Done") fibaro:sleep(60*60*1000) fibaro:debug(os.date("%a %d/%m", os.time()).." 2H Done") fibaro:sleep(60*60*1000) fibaro:debug(os.date("%a %d/%m", os.time()).." 3H Done") if fibaro:getValue(id2["MODES_AUTO_MANUEL"], "ui.ModeRez.value") == "Manuel" and fibaro:getValue(id2["MODES_AUTO_MANUEL"], "ui.Mode1er.value") == "Manuel" and fibaro:getValue(id2["MODES_AUTO_MANUEL"], "ui.ModeGarage.value") == "Manuel" then NewState = "Automatique" fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeRez.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.Mode1er.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.ModeGarage.value", NewState); fibaro:call(selfId, "setProperty", "ui.HouseMode.value", NewState); fibaro:call(id2["MODES_AUTO_MANUEL"], "setProperty", "ui.LastChange.value", "Tout "..NewState.." à "..os.date("%H:%M")); fibaro:debug(os.date("%a %d/%m", os.time()).." Set all modes to "..NewState); end fibaro:debug(os.date("%a %d/%m", os.time()).." Time's up set mode Auto") --fibaro:setGlobal("House_Mode", "Scheduler") Voilà un petit apperçu et un bon cas d'utilisation de LABELS au lieu de VG Voici le VD: Et voici les icônes Modes_Auto-Manuel.vfib
  10. Ce module virtuel va crée automatiquement les variables si elles n'existent pas. Comment utiliser la table : "Nom de la variable", "1" (si prédéfinie) ou "0" (Variable Globale), "Valeur par défault", '"Valeur Prédéfinie"' -- Table variable Globale local VG_Table = { "Mode", "1", "Absent", '"Maison", "Vacances"', -- Variable Prédéfinie Mode "MPRInfo", "0", "100", -- Variable MPRInfo "Jour", "1", "Oui", '"Non"' -- Variable Prédéfinie Jour } Création des Variables Globales et Prédéfinies --************************ --Creation de Variable --- --************************ function VG_Creation(VG_Nom, VG_isEnum, VG_Value, VG_enumValues) if (fibaro:getGlobal(VG_Nom) == "") then fibaro:debug(VG_Nom.." "..VG_isEnum.." "..VG_Value) newVar = {} newVar.name = VG_Nom newVar.isEnum = tonumber(VG_isEnum) if tonumber(VG_isEnum) == 0 then newVar.value = VG_Value end HC2 = Net.FHttp("127.0.0.1", 11111) HC2:POST("/api/globalVariables", json.encode(newVar)) --------------------------------------------- -- création des valeurs prédéfinies si Besoin --------------------------------------------- if tonumber(VG_isEnum) == 1 then VG_Predefinie = '{"value":"'..VG_Value ..'","isEnum":true,"enumValues":'..'["'..VG_Value..'", '..VG_enumValues..']' ..'}' HC2:PUT("/api/globalVariables/"..VG_Nom, VG_Predefinie) end end end Lecture du tableaux et création si besoin des variables ---------------------------------------------------- -- Execution du programme ---------------------------------------------------- local j = 1 local NbreVG = 0 while VG_Table[j] ~= nil do if tonumber(VG_Table[j+1]) == 0 then fibaro:debug((NbreVG+1).." - Variable Globale") VG_Creation(VG_Table[j], VG_Table[j+1], VG_Table[j+2]) j=j+3 elseif tonumber(VG_Table[j+1]) == 1 then fibaro:debug((NbreVG+1).." - Variable prédéfinie") VG_Creation(VG_Table[j], VG_Table[j+1], VG_Table[j+2], VG_Table[j+3]) j=j+4 else fibaro:debug("Erreur dans la table VG") end NbreVG = NbreVG + 1 end fibaro:debug("Nombres de variable dans le tableau : " ..NbreVG) J'ai simplement ajouter un bouton aux VD Variables Globales de STEVEN comme cela on voit de suite si la variable n'est pas crée Petit Exercice : Optimiser ce code qui et fonctionnel mais pas très académique, il permet de crée les valeurs de la variable prédéfinie : if tonumber(VG_isEnum) == 1 then VG_Predefinie = '{"value":"'..VG_Value ..'","isEnum":true,"enumValues":'..'["'..VG_Value..'", '..VG_enumValues..']' ..'}' fibaro:debug(VG_Predefinie) HC2:PUT("/api/globalVariables/"..VG_Nom, VG_Predefinie) end Variables_Globales.vfib
  11. OJC

    Heating Manager

    HEATING MANAGER v. 3.1.2 - 16/12//2017 Heating Manager est un programme permettant d'utiliser le Home Center 2 pour gérer avec une grande souplesse le chauffage d'une habitation, en permettant de franchir une étape supplémentaires dans la gestion de celui-ci. En effet, s'il est parfaitement capable de fonctionner en suivant une planification, Heating Manager permet de passer à l'étape suivante et d'exploiter pleinement les potentialités de la domotique en se passant totalement de planification et en gérant le chauffage sur une base événementielle exclusivement dynamique. Heating Manager, qui propose de réguler le chauffage sur un mode proportionnel avec prise en compte des déperditions (Ubat) ou sur un mode classique avec hystérésis, est compatible avec n'importe quel système de commande de chauffage, y compris des modules virtuels. Il peut fonctionner en tout ou partie en mode planification via l'utilisation des panneaux de chauffage natifs du Home Center 2, de modules dédiés ou de variables globales. En mode événementiel, il peut s'appuyer sur n'importe quelle propriété de n'importe quel module, virtuel ou non, ainsi que sur des variables globales. L'utilisation de boucles conditionnelles dans la configuration permet en outre de faire varier cette configuration en fonction de n'importe quelle condition. Ces développements doivent beaucoup aux échanges stimulants intervenus sur ce fil de discussion, qui m'ont amené à aller bien plus loin que ce qui était prévu au départ, à savoir simplement pouvoir utiliser les panneaux de chauffage avec les modules fils pilote proposés par Qubino... Que tous soient remerciés , ainsi que ceux qui relèvent des bugs et permettent d'améliorer le script. _ _ _ PRE-REQUIS Ce programme a été conçu et testé sur le Home Center 2 tournant avec le firmware v. 4.140. Il ne requiert aucun matériel particulier et peut s'adapter facilement à toutes les configurations. _ _ _ INSTALLATION 1. Pour une utilisation en tout ou partie en mode planification, il faut commencer par définir les plannings de chauffe souhaités. La première étape dans cette optique de fonctionnement est de définir un planning de chauffe dans lequel Heating Manager ira chercher la température de consigne à atteindre. Ce planning de chauffe peut être mis en place en utilisant les panneaux de chauffage fournis nativement par le Home Center 2. Attention cependant, un bug a été constaté, évoqué dans ce fil, entraînant l'absence de prise en compte du changement de température de consigne après minuit. Il peut également être mis en place en utilisant n'importe quel module virtuel ou bien celui, basique, fourni avec Heating Manager >>>> Heating_Provider.vfib Pour utiliser ce module virtuel, il faut adapter la configuration donnée en exemple à votre cas en modifiant, et en ajoutant le cas échéant, les étiquettes, chaque étiquette correspondant à une zone de chauffage. La définition du planning de chauffe pour chacun de ces zones intervient dans le main loop du module virtuel, dans la partie Configuration : HeatingManager:add(zone, day, time, temperature) zone correspond au nom d''une étiquette du module virtuel day est soit un ou plusieurs jours de la semaine (en anglais e.g. {"monday","friday"}), soit "weekday" (du lundi au vendredi), soit "weekend", soit "week" time est l''heure à laquelle la température de consigne devra être appliquée "hh:mm" temperature est la température de consigne devant être appliquée à compter de l''horaire défini juste avant Il est important que la construction du planning de chauffe soit faite de manière chronologique, le module virtuel ne faisant pas de tri chronologique, ce qui peut entraîner un comportement s'écartant de celui attendu. 2. Pour une utilisation en tout ou partie en mode événementiel, il faut importer un thermostat par pièce concernée >>>> Thermostat.vfib Ce module virtuel permet de définir la température de consigne (mode Confort et mode Economique) pour la pièce, de forcer l'un de ces deux modes ou de passer en mode manuel avec un minuteur permettant de retourner au mode automatique. Les ordres donnés par l'intermédiaire de ce module viruel l'emportent sur toute autre évènement défini dans la configuration de Heating Manager. Il faut juste mettre un module virtuel dans chaque pièce. Sa détection par Heating Manager se fait automatiquement. 3. [OPTIONNEL] Pour afficher de manière centralisée les températures de consigne en cours, il faut installer le module virtuel Heating Viewer >>>> Heating_Viewer.vfib Pour le bon fonctionnement de ce module, chaque pièce dont le chauffage est géré par Heating Manager doit avoir une étiquette, dont l'ID doit être le nom de cette pièce débarrassé de tous les accents, espaces et autres caractères exotiques. Ainsi, pour la pièce "Séjour Principal #1", l'ID de l'étiquette doit être "SejourPrincipal1". Les étiquettes inutilisées peuvent être supprimées, tout comme il peut être ajouté autant d'étiquettes que nécessaire. 4. Création d'une scène en mode Lua avec copier-coller du code >>>> Heating Manager - Scène.lua La configuration de Heating Manager est réalisée par l'exécution de neuf fonctions différentes à paramétrer dans la partie USER CONFIGURATION ZONE qui se trouve à partir de la ligne 100 du code. self:setConfiguration(checkConfig, oldLastTempUpdate, logInfo, pushWarnErrLog, pushTo, popupWarnErrLog, logMemory) checkConfig est un booléen dont la valeur par défaut est true, qui permet de définir si Heating Manager doit contrôler de manière approfondie la configuration (existence des pièces, des modules, des propriétés de modules, des variables globales, etc.) Une fois que votre configuration est rodée et fonctionne sans problème, vous pouvez passer ce paramètre à false. oldLastTempUpdate est un nombre dont la valeur par défaut est 180 et qui est le nombre de minutes depuis la dernière remontée de température d'une sonde intérieure au-delà duquel Heating Manager adressera un message d'alerte et arrêtera la chauffe. logInfo est un booléen dont la valeur par défaut est true et qui permet de définir si l'intégralité des messages doit s'afficher dans la fenêtre de debug, ou uniquement les plus importants (action, survenance d'un événement, changement de la température de consigne). pushWarnErrLog est un booléen dont la valeur par défaut est false et qui permet de définir si les messages d'alerte et d'erreur doivent faire l'objet d'une notification Push. pushTo est une table contenant l'ID des téléphones mobiles auxquels envoyer les notification Push si le paramètre précédent est à true. popupWarnErrLog est un booléen dont la valeur par défaut est false et qui permet de définir si les messages d'alerte et d'erreur doivent faire l'objet d'une notification dans le centre de notification du Home Center 2. logMemory est un booléen dont la valeur par défaut est true et qui permet d'afficher dans la fenêtre de debug, toutes les cinq minutes, la mémoire utilisée par Heating Manager. self:setProportionalMode(default_kP, auto_kP, default_kT, cycle, minCycle, defaultSetpoint) Cette fonction ne doit être utilisée que si vous souhaitez utiliser le mode de régulation proportionnel. default_kP est un nombre dont la valeur par défaut est 60 et qui est le coefficient proportionnel utilisé par Heating Manager dans le cadre de la régulation proportionnelle si aucun coefficient particulier n'est défini pour un radiateur donné. auto_kP est un booléen dont la valeur par défaut est true et qui permet de définir si Heating Manager doit adapter le coefficient proportionnel en fonction de l'expérience acquise lors des cycles de chauffe. default_kT est un nombre dont la valeur par défaut est 1 et qui est le coefficient de déperditions thermiques (Ubat) utilisé par Heating Manager dans le cadre de la régulation proportionnelle si aucun coefficient particulier n'est défini pour un radiateur donné. La valeur 1 correspond à une maison bien isolée. Pour un bâtiment mal isolé, ce coefficient peut être fixé à 3. cycle est un nombre dont la valeur par défaut est 15 et qui est la durée d'un cycle de chauffage en minutes, au sein duquel s'insère la période de chauffe calculée par Heating Manager. minCycle est un nombre dont la valeur par défaut est 1 et qui est la durée minimale en minutes d'une période de chauffe. defaultSetpoint est soit comfort, soit eco (sans guillemets) et permet de déterminer, uniquement pour un fonctionnement en mode événementiel, si la consigne à appliquer en dehors de tout événement est la température de confort définie dans le thermostat virtuel ou la température économique. La valeur par défaut est comfort. self:setHysteresisMode(hysteresis, cycle, defaultSetpoint) Cette fonction ne doit être utilisée que si vous souhaitez utiliser le mode de régulation par hystérésis. hysteresis est un nombre dont la valeur par défaut est 0 et qui est l'écart en degré entre la température courante et la température de consigne au-delà ou en-deça duquel le chauffage sera démarré. cycle est un nombre dont la valeur par défaut est 15 et qui est l'intervalle en minutes entre deux comparaisons de la température courante et de la température de consigne. defaultSetpoint est soit comfort, soit eco (sans guillemets) et permet de déterminer, uniquement pour un fonctionnement en mode événementiel, si la consigne à appliquer en dehors de tout événement est la température de confort définie dans le thermostat virtuel ou la température économique. La valeur par défaut est comfort. self:setEventDefaults(eCumulative, eSetpoint, eDuration, eStep, ePersistence) eCumulative est un booléen dont la valeur par défaut est true et qui permet de définir si les conditions d'un événement doivent toutes être réalisés pour que l'événement soit considéré comme survenu, ou si la réalisation d'une seule condition est suffisante. Il s'agit ici de définir la valeur par défaut qui sera utilisée à défaut de paramétrage contraire lors du paramétrage de chaque événement. eSetpoint est un nombre dont la valeur par défaut est 18 et qui permet de définir la température de consigne qui sera appliquée par défaut en cas de survenance d'un événement lorsqu'aucune température de consigne propre n'est définie lors du paramétrage de l'événement. eDuration est un nombre dont la valeur par défaut est 0 et qui permet de définir la durée en minutes devant s'écouler entre la survenance de l'événement et l'application de la température de consigne correspondante, permettant ainsi de prévoir une diminution ou une augmentation graduelle de la température de consigne. eStep est un nombre dont la valeur par défaut est 0.5 et qui permet de définir les étapes de diminution ou d'augmentation graduelle de la température de consigne. ePersistence est un nombre dont la valeur par défaut est 0 et qui permet de définir la durée par défaut pendant laquelle Heating Manager continuera à considérer qu'un événement est réalisé à partir de l'instant où les conditions de sa réalisation ne sont plus remplies. Si les conditions sont à nouveau remplies pendant le délai de persistence, Heating Manager agira comme si elles n'avaient jamais cessé d'être remplies. self:addHeater(idRoom, idHeater, idSonde, localkP, localkT) Cette fonction permet de déclarer les radiateurs qui seront gérés par Heating Manager. La fonction doit être paramétrée pour chaque radiateur. idRoom est l'ID de la pièce définie dans le Home Center 2 dans laquelle se trouve le module de commande du radiateur. idHeater désigne un module de commande d'un radiateur sous forme de table {ID du module, instruction pour mise en route, instruction pour arrêt, valeur à l'arrêt} : ID du module est l'ID d'un module, virtuel ou non, permettant de commander la mise en route ou l'arrêt du chauffage. instruction pour mise en route est soit la commande à transmettre s'il s'agit d'un module 'réel' ("turnOn" par exemple), soit le numéro d'ordre du bouton d'un module virtuel. instruction pour arrêt est soit la commande à transmettre s'il s'agit d'un module 'réel' ("turnOff" par exemple), soit le numéro d'ordre du bouton d'un module virtuel. valeur à l'arrêt est la valeur de la propriété value lorsque le radiateur est arrêté, et est utilisé pour éviter d'envoyer les commandes de mise en route et d'arrêt inutilement. idSonde désigne une sonde de température qui peut être définie spécifiquement pour un radiateur s'il n'est pas asservi à la sonde de température principale de la pièce définie dans le Home Center 2. Il peut s'agir d'une sonde de température proprement dite ou d'un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Il peut également s'agir du nom d'une variable globale dans laquelle est stockée la température. localkP permet de définir un coefficient proportionnel fixe qui sera utilisé pour calculer la commande de chauffe de ce radiateur. localkT permet de définir un coefficient de déperditions thermiques qui sera utilisé pour calculer la commande de chauffe de ce radiateur. self:addEvent(idRoom, idEvent, conditions, cumulative, setpoint, duration, persistence) Cette fonction permet de définir les événements qui entraîneront une modification de la température de consigne (ouverture d'une fenêtre, absence temporaire ou prolongée, lumière allumée ou éteinte...). idRoom est l'ID de la pièce concernée par l'événement, ou une table contenant les IDs de plusieurs pièces concernées par l'événement. idEvent est le nom de l'événement, qui sera affiché dans la fenêtre de debug lors de sa survenance. conditions est une table contenant les différentes conditions devant être réalisées, ensemble ou séparément, pour que l'événement soit considéré comme survenu et la température de consigne modifiée en conséquence. Cette table contient elle-même une table par condition (il y a donc forcément une double accolade au début et à la fin), sous la forme {nom de variable globale, opérateur ("==", "~=", ">=", "<=", ">", "<"), valeur à vérifier, durée en minutes devant s'être écoulée depuis que le résultat de la comparaison est vrai} ou {ID d'un module, nom de la propriété d'un module, opérateur ("==", "~=", ">=", "<=", ">", "<"), valeur à vérifier, durée en minutes devant s'être écoulée depuis que le résultat de la comparaison est vrai}. cumulative est un booléen permet de définir, pour cet événement particulier, si sa survenance implique la réalisation de toutes les conditions ou si une seule est suffisante. setpoint permet de définir la température de consigne devant être appliquée lorsque l'événement survient. Dans le cadre du mode de fonctionnement événementiel, vous pouvez utiliser les variables comfort et eco qui font références aux températures définies pour la pièce avec le module virtuel Thermostat. duration est la durée en minutes devant s'écouler entre la survenance de l'événement et l'application de la température de consigne correspondante, permettant ainsi de prévoir une diminution ou une augmentation graduelle de la température de consigne. persistence est un nombre qui permet de définir la durée pendant laquelle Heating Manager continuera à considérer que l'événement est réalisé à partir de l'instant où les conditions de sa réalisation ne sont plus remplies. Si les conditions sont à nouveau remplies pendant le délai de persistence, Heating Manager agira comme si elles n'avaient jamais cessé d'être remplies. Dans le cadre de la configuration, cette fonction peut s'insérer dans une boucle conditionnelle permettant de ne laisser l'événement se réaliser que sous des conditions précises, par exemple d'horaires. self:addGlobalEvent(idEvent, conditions, cumulative, setpoint, duration, persistence) Cette fonction permet de définir un événement s'appliquant à toutes les pièces dont le chauffage est géré par Heating Manager, et se configure exactement de la même manière que la précédente, le paramètre idRoom en moins. Attention : le fait que l'événement soit global ne signifie pas qu'il l'emporte sur les événements spécifiques d'une pièce. Heating Manager contrôle les événements les uns à la suite des autres pour chaque pièce, dans l'ordre de leur configuration. Dès que les conditions d'un événement sont remplies, le programme cesse la boucle et n'analyse pas les autres événements déclarés. self:setIndoorSonde(idRoom, idSonde) Cette fonction permet de définir la sonde de température d'une pièce si vous ne souhaitez pas utiliser la sonde de température principale définie dans le Home Center 2. idRoom est l'ID de la pièce concernée. idSonde désigne une sonde de température proprement dite ou un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Il peut également s'agir du nom d'une variable globale dans laquelle est stockée la température. self:setSetpoint(idRoom, idSetpoint) Cette fonction permet de définir, pour une pièce donnée, la source de la température de consigne qui devra être appliquée. L'utilisation de cette fonction n'est requise que dans le cas de l'utilisation du mode planification, et est inutile lorsque le chauffage de la pièce est effectué selon le mode événementiel. idRoom est l'ID de la pièce concernée. idSetpoint désigne la source de la température de consigne et peut être : l'ID d'un panneau de chauffage natif du Home Center 2. une table sous la forme {ID du module, propriété du module contenant la température de consigne} s'il s'agit d'un module, virtuel ou non. le nom d'une variable globale qui contiendra la température de consigne. self:setOutdoorSonde(idSonde) Cette fonction permet définir une sonde de température extérieure. Elle n'est utilise que dans le cas de la régulation proportionnelle qui tient compte de la température extérieure, et est inutile pour une régulation à base d'hystérésis. idSonde désigne une sonde de température proprement dite ou un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Lorsqu'aucune sonde de température extérieure n'est définie et que le mode de régulation proportionnel est utilisé, Heating Manager utilise la température fournie par le plugin Météo. 5. Mise à jour depuis une version précédente Cette nouvelle version apporte des modifications en profondeur du programme et de la manière de le configurer. Il n'est donc pas possible de faire simplement un copier-coller de la configuration d'une version précédente à la 3.0, qui était éclatée entre la scène et un module virtuel, mais il est nécessaire de reprendre la configuration depuis le départ. Depuis la version 3.0, il est impératif de modifier les fonctions self:addEvent pour ajouter dans les conditions le paramètre operator : "==", "~=", ">=", "<=", ">" ou "<". Si le contrôle de configuration est activé, un message d'erreur s'affichera dans la fenêtre de debug sans faire planter le programme. L'ajout du paramètre ePersistence dans la fonction self:setConfiguration et persistent dans les fonctions self:addEvent n'est pas indispensable puisqu'il s'agit du dernier paramètre de ces fonctions. A défaut de les ajouter, c'est la valeur par défaut (0) qui s'appliquera. _ _ _ ROADMAP [VIDE] _ _ _ ICONES
  12. Gestion simple des Variables Globale en LUA Le script que je partage avec vous va vous permettre de gérer simplement les Variables globales et Variables globales prédéfinie en LUA. C'est une adaptation du code de STEVEN Avantage : Il permet de faire une sauvegarde des Variables globales ce qui est bien pratique lorsque l'on fait un recovery Il permet de créé des variables globales prédéfinie ou pas très simplement à partir d'une scène ou d'un VD sans avoir à sortir artillerie lourde. Voici le code a mettre dans une Scéne : --[[ %% properties %% globals GestionVG --]] local trigger = fibaro:getSourceTrigger() local variables = {} local variablesASupprimer ={} -- creation de ou des VG avec la variable GestionVG if (trigger['type'] == 'global') then fibaro:debug('Global variable source = ' .. trigger['name']) variables = json.decode((fibaro:getGlobal('GestionVG'))); if variables == nil then fibaro:abort() end -- creation de ou des VG manuellement ou par une autre scène ou un appel API elseif (trigger['type'] == 'other') then fibaro:debug('Global variable source = ' .. 'Other source.') variables = { {nom = "GestionVG", valeur = ""}, -- Gestion de VG -- Ex : Variable Globale predefini avec valeur1 pour valeur par default {nom = "Test1", valeur = "Valeur1", choix = {"Valeur2", "Valeur3"}}, -- Ex : Variable Globale qui à pour valeur 0 {nom = "Test2", valeur = "0"}, } variablesASupprimer = { {nom = "Test1"}, {nom = "Test2"} } end ------------------------------------------------- ---- Merci a STEVEN pour ce code -- ----------------------------------------------- -- Supprime une variable -- ----------------------------------------------- function supprimer(nom) local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/globalVariables/"..nom, { options = { method = 'DELETE' } , success = function(response) fibaro:debug(nom .. " supprimée avec succès") end, error = function(response) fibaro:debug(nom .. " ERROR !!!") end, }) end -- ----------------------------------------------- -- Modifie une variable -- ----------------------------------------------- function modifier(nom, valeur, choix) local variable = {} variable.value = valeur variable.isEnum = false if (type(choix) ~= "nil") then variable.isEnum = true table.insert(choix, 1, valeur) variable.enumValues = choix end local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/globalVariables/"..nom, { options = { method = 'PUT', data = json.encode(variable) }, success = function(response) fibaro:debug(nom .. " modifiée avec succès") end, error = function(response) fibaro:debug(nom .. " ERROR !!!") end, }) end -- ----------------------------------------------- -- Ajoute une variable -- ----------------------------------------------- function ajouter(nom, valeur, choix) local enum = 0 if (type(choix) ~= "nil") then enum = 1 end local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/globalVariables", { options = { method = "POST", data = json.encode({name=nom, isEnum=enum}) }, success = function(response) fibaro:debug(nom .. " créé avec succès") modifier(nom, valeur, choix) end, error = function(response) fibaro:debug(nom .. " ERROR !!!") end, }) end -- ----------------------------------------------- -- Voir si une variable existe ou non -- et la modifier ou créer -- ----------------------------------------------- function traiter(nom, valeur, choix) if (fibaro:getGlobalValue(nom) == nil) then ajouter(nom, valeur, choix) else -- modifier(nom, valeur, choix) end end ---------------------------------------------------- -- Execution du programme ---------------------------------------------------- for _,v in ipairs(variables) do traiter(v.nom, v.valeur, v.choix) end for _,v in ipairs(variablesASupprimer) do supprimer(v.nom) end Dans un premier temps il va falloir exécuter le script manuellement afin qu'il crée la VG GestionVG cette VG va être utiliser pour crée les variables globale à partir de n'importe quel script Lua Exemple d'utilisation : Création d'une variables globales "Test2" avec la valeur 0 local variables = { {nom = "Test2", valeur = "0"}, } fibaro:setGlobal('GestionVG',json.encode(variables)) Création d'une variables globales prédéfinie "Test1" avec Valeur1 , Valeur2 et Valeur3, vValeur1 sera la valeur par défaut dans cette exemple local variables = { {nom = "Test1", valeur = "Valeur1", choix = {"Valeur2", "Valeur3"}}, } fibaro:setGlobal('GestionVG',json.encode(variables)) Création de plusieurs variable globales prédéfinie ou pas en une seul fois local variables = { {nom = "Test1", valeur = "Valeur1", choix = {"Valeur2", "Valeur3"}}, {nom = "Test2", valeur = "0"}, } fibaro:setGlobal('GestionVG',json.encode(variables)) Création et suppression de variables via la scéne il faut modifier le code suivant, la méthode est la même que les exemples si dessus. Lors de l'exécution de la scene en mode manuel les variables seront créés si elle n'existe pas. elseif (trigger['type'] == 'other') then fibaro:debug('Global variable source = ' .. 'Other source.') variables = { {nom = "GestionVG", valeur = ""}, -- Gestion de VG -- Ex : Variable Globale predefini avec valeur1 pour valeur par default {nom = "Test1", valeur = "Valeur1", choix = {"Valeur2", "Valeur3"}}, -- Ex : Variable Globale qui à pour valeur 0 {nom = "Test2", valeur = "0"}, } variablesASupprimer = { {nom = "Test1"}, {nom = "Test2"}, } Ce code est fonctionnel chez moi, par manque de temps je ne pourrais vous aidez si vous avez des soucis de compréhension sur la création des VG ou leurs suppression
  13. cboubou

    Module Virtuel "smartvmc"

    Bonjour la communauté, Je vous propose aujourd'hui mon module virtuel "SmartVMC". Ce dernier me permet de piloter de manière automatique ma VMC en fonction de la qualité de l'air de ma maison : On allume la VMC si le taux moyen d'humidité relative est supérieur à 60% OU si la concentration moyenne de CO2 est supérieure à 1000 ppm. Le traitement s'arrêtera si le taux moyen d'humidité relative est inférieur ou égal à 55% ET si la concentration moyenne de CO2 est inférieure ou égale à 900 ppm. Le but étant de ne pas allumer/éteindre la VMC dès que l'on atteint la limite de 60% ou de 1000 ppm. Les données sur la qualité de l'air (humidité relative et concentration de CO2) sont extraites de ma Netatmo par le biais du plugin idoine disponible dans la V4. Ma configuration matérielle est la suivante : VMC simple flux, hygroréglable, Aldès, MicroWatt. Home Center 2 en version v4.033. WallPlug Fibaro pour piloter la VMC. Station Netatmo avec modules additionnels. Le module virtuel se présente de la sorte : Un visuel des moyennes d'humidité relative et de concentration de CO2. Un bouton permettant d'analyser à l'instant "t" l'air de la maison. Un visuel de l'état actuel de la VMC. Un bouton de marche forcée de la VMC. Un bouton d'arrêt complet de la VMC. Un bouton pour basculer la VMC en mode automatique. La date de la dernière analyse de l'air. Les 4 états différents de la VMC sont les suivants : Marche Forcée Arrêt Complet Auto (En cours...) Auto (Pause) Il est nécessaire de créer 2 variables globales : Une première variable globale "VMC" est utilisée afin de savoir si la VMC est : en marche automatique, en pause, en marche forcée ou arrêtée (Auto, Pause, Forcée, Arrêtée). Une seconde variable globale "RecyclAir" est utilisée afin de savoir si la VMC est déjà en train d'assainir l'air, par le biais de ce traitement (Oui, Non). J'ai commenté le code afin d'en faciliter la compréhension. NB : Il peut être envisageable pour les personnes possédant une VMC à 2 vitesses que le mode "Auto (En cours...)" corresponde à la grande vitesse et que le mode "Auto (Pause)" corresponde à la petite vitesse. Voici les icônes (2 variantes) : Orange => Marche Forcée Rouge => Arrêt Complet Vert => Auto (En cours...) Bleu => Auto (Pause) Les originaux qui m'ont servi de base sont ici : http://www.domotique...zibase/?p=25155 Vous trouverez également de magnifiques icônes pour la Netatmo ici (merci Stef). ChangeLog => v1.0 : Création du module. v1.1 : Ajout du push lors du passage "En cours" <=> "Pause". Modification des conditions du passage au mode "Auto". Ajout d'un contrôle sur l'état du plugin Netatmo pour mode "Auto". SmartVMC.vfib
  14. jojo

    Backup Variables

    Le soucis de bon nombre d'entre nous est le fait qu'on soit lié à un backup sur une clé USB propriété de Fibaro. L'excellent tuto de Lazer explique comment faire un backup de la clé, mais il faut avoir des connaissances Linux, que perso je n'ai pas. Merci à mprinfo pour son tuto sur la création des variables en LUA qui m'a donné l'idée et les premières infos pour le restore. Merci également à Steven pour son script de génération des ID dont je me suis inspiré pour faire le backup. Alors, ici, je vous présente mon premier couple scène / VD de backup / restore, d'une série que j'espère longue … Avec la scène en mode débug, on crée le backup des variables. On colle le résultat du debug de la scène dans le bouton restore du VD (que vous exportez sur votre disque dur), et en cliquant sur le bouton Restore, il recrée les variables si elles n'existaient pas. Si vous lancez le restoreen Debug, vous avez un débug détaillé de ce qu'il a fait. C'est très utile pour faire un restore sur une nouvelle box (ou après un recovery) Les instructions se trouvent dans le code de la main loop. Version 2.0 : Backup_Variables_v2.0.vfib Backup_Variables_v2.0.lua Version 1.0 : Backup_Variables_v1.0.vfib Backup_Variables_v1.0.lua
  15. Watchdog Version 1.3 Voici une scène permettant de surveiller le fonctionnement des Scènes et Main Loop de Modules Virtuels sur Home Center 2 en version 4.x. Pour ce faire, les messages de la fenêtre de Debug sont analysés. De plus, pour les scènes uniquement, le nombre d'instances est compté. En cas de problème détecté, la scène ou le virtual device considéré est automatiquement redémarré, et une notification peut être envoyée. Copier/coller le script LUA suivant dans une nouvelle scène : --[[ %% autostart %% properties %% globals --]] -------------------------------------------------- -- Scene : Watchdog -- Author : Lazer -- Version : 1.3 -- Date : June 2017 -------------------------------------------------- -- User variables local intervalle = 60 local delay = 15*60 local watchdog = { } local userID = {} -- Email local smartphoneID = {} -- Push local sms = { ["VD_ID"] = 0, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local debug = false -- -- Message function -- function Message(color, message) if color and color ~= "" then fibaro:debug('<span style="color:'..color..';">'..(message or '<nil>')..'</span>') else fibaro:debug(message or '<nil>') end end -- -- Notification function -- function Notification(message, param) local message = message or "<vide>" Message("yellow", "Notification : "..message) if param then for _, notif in ipairs(param) do if debug then Message("grey", notif) end -- Envoi Push if notif == "push" and smartphoneID then for _, id in ipairs(smartphoneID) do if debug then Message("grey", "Send Push smartphone ID : "..id) end fibaro:call(id, "sendPush", message) end -- Envoi Email elseif notif == "email" and userID then for _, id in ipairs(userID) do if debug then Message("grey", "Send Email user ID : "..id) end fibaro:call(id, "sendEmail", "HC2 Watchdog", message) end -- Envoi SMS elseif notif == "sms" and sms then if debug then Message("grey", "Send SMS : VD_ID="..(sms["VD_ID"] or 0).." VD_Button="..(sms["VD_Button"] or "0").." VG_Name="..(sms["VG_Name"] or "")) end fibaro:setGlobal(sms["VG_Name"], message) if sms["VD_ID"] and tonumber(sms["VD_ID"])>0 and sms["VD_Button"] and tonumber(sms["VD_Button"])>0 then fibaro:call(sms["VD_ID"], "pressButton", sms["VD_Button"]) end end end else Message("orange", "Warning : no notification options given") end end -- -- Restart function -- function Restart(type, id, restart, notification, reason) Message("blue", 'Restart '..type..'('..id..')') -- Prepare API URL local getURL = "" local putURL = "" if type:lower() == "scene" then getURL = 'http://127.0.0.1:11111/api/scenes/'..id putURL = 'http://127.0.0.1:11111/api/scenes/'..id elseif type:lower() == "vd" then getURL = 'http://127.0.0.1:11111/api/virtualDevices/'..id putURL = 'http://127.0.0.1:11111/api/virtualDevices/'..id end -- Load VD/Scene local httpClient = net.HTTPClient() httpClient:request(getURL, { success = function(response) if response.status == 200 then local jsonTable = json.decode(response.data) local name = jsonTable.name or "" if restart and restart == true then -- Add new line at end of scene lua code if type:lower() == "scene" and jsonTable.lua then jsonTable.lua = jsonTable.lua .. "\n" response.data = json.encode(jsonTable) end -- Save VD/Scene httpClient:request(putURL, { success = function(response) if response.status == 200 then Message("green", type.."("..id..") successfully restarted") Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") a été redémarré : "..(reason or "???"), notification) else Message("red", type.."("..id..") Error : status="..tostring(response.status)) Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end end, error = function(err) Message("red", type.."("..id..") Error : "..err) Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end, options = { method = 'PUT', -- headers = { -- ["content-type"] = 'application/x-www-form-urlencoded;' -- }, data = response.data } }) else Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") doit être redémarré manuellement : "..(reason or "???"), notification) end else Message("red", type.."("..id..") Error : status="..tostring(response.status)) Notification('Watchdog : '..type..' ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end end, error = function(err) Message("red", type.."("..id..") Error : "..err) Notification('Watchdog : '..type..' ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end, options = { method = 'GET' } }) end -- function -- -- Check function -- function Check(interval) Message(nil, "Check") -- Browse VD/Scene list local httpClient = net.HTTPClient() local elements = #watchdog for i = 1, elements do -- Initialization local countscene_found = false if debug then Message(nil, "Check : type="..watchdog[i].type.." id="..watchdog[i].id) end -- Check number of running scene instances if watchdog[i].type:lower() == "scene" and watchdog[i].count and watchdog[i].count > 0 then local countScenes = fibaro:countScenes(watchdog[i].id) if countScenes < watchdog[i].count then Message("orange", watchdog[i].type..'('..watchdog[i].id..') '..countScenes..' running instance') countscene_found = true Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, countScenes..' instance') elseif debug then Message("green", watchdog[i].type..'('..watchdog[i].id..') '..countScenes.." running instance") end end if countscene_found == false then -- Do not enter this loop if scene has already been restarted -- Prepare API URL local getURL = "" if watchdog[i].type:lower() == "scene" then getURL = "http://127.0.0.1:11111/api/scenes/"..watchdog[i].id.."/debugMessages" elseif watchdog[i].type:lower() == "vd" then getURL = "http://127.0.0.1:11111/api/virtualDevices/"..watchdog[i].id.."/debugMessages/0" else Message("red", "Error : unknown type value") end if getURL ~= "" then if debug then Message("grey", getURL) end -- Load VD/Scene debug messages httpClient:request(getURL, { success = function(response) if response.status == 200 then if response.data and response.data ~= "" then local jsonTable = json.decode(response.data) local current_timestamp = os.time() local oldest_timestamp = current_timestamp local match_found = false local no_match_found = false local reason = "" -- Reverse browsing of debug messages for j = #jsonTable, 1, -1 do oldest_timestamp = jsonTable[j].timestamp -- Check if debug message match lookup string within allowed interval if watchdog[i].match.text and watchdog[i].match.text ~= "" and watchdog[i].match.interval > 0 and jsonTable[j].txt:match(watchdog[i].match.text) then if jsonTable[j].timestamp > current_timestamp - watchdog[i].match.interval then if debug then Message("green", watchdog[i].type..'('..watchdog[i].id..') Found string "'..watchdog[i].match.text..'"') end match_found = true end end -- Check if debug message match forbidden string if watchdog[i].no_match.text and watchdog[i].no_match.text ~= "" and jsonTable[j].txt:match(watchdog[i].no_match.text) then Message("orange", watchdog[i].type..'('..watchdog[i].id..') Found string "'..watchdog[i].no_match.text..'"') no_match_found = true reason = os.date('%H:%M:%S', (jsonTable[j].timestamp or 0)) .. " " .. jsonTable[j].type .. " : " .. jsonTable[j].txt break end if watchdog[i].no_match.type and watchdog[i].no_match.type ~= "" and jsonTable[j].type == watchdog[i].no_match.type then Message("orange", watchdog[i].type..'('..watchdog[i].id..') Found type "'..watchdog[i].no_match.type..'"') no_match_found = true reason = os.date('%H:%M:%S', (jsonTable[j].timestamp or 0)) .. " " .. jsonTable[j].type .. " : " .. jsonTable[j].txt break end end -- for if debug and oldest_timestamp > current_timestamp - watchdog[i].match.interval then Message("grey", watchdog[i].type..'('..watchdog[i].id..') oldest debug timestamp more recent than interval') end -- Restart VD/Scene if watchdog[i].match.text and watchdog[i].match.text ~= "" and watchdog[i].match.interval > 0 and match_found == false and oldest_timestamp < current_timestamp - watchdog[i].match.interval then Message("orange", watchdog[i].type..'('..watchdog[i].id..') String "'..watchdog[i].match.text..'" not found') reason = 'Chaine « ' .. watchdog[i].match.text .. ' » non trouvée' if #jsonTable > 0 then reason = reason .. ', dernier message : ' .. os.date('%H:%M:%S', (jsonTable[#jsonTable].timestamp or 0)) .. ' « ' .. (jsonTable[#jsonTable].txt or "<nil>") .. ' »' end Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, reason) --if watchdog[i].no_match.text and watchdog[i].no_match.text ~= "" and no_match_found == true then elseif no_match_found == true then Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, reason) end else Message("red", "Error : empty response") end else Message("red", "Error : status=" .. tostring(response.status)) end end, error = function(err) Message("red", 'Error : ' .. err) end, options = { method = 'GET' } }) end end end -- for -- Wait if interval and interval > 0 then setTimeout(function() Check(interval) end, interval*1000) end end -- function -- -- Main loop -- local trigger = fibaro:getSourceTrigger() if trigger["type"] == "autostart" then Message(nil, "Watchdog instance autostart") -- Check function call delayed to prevent killing all other scenes not already started right after HC2 boot setTimeout(function() Check(intervalle) end, delay*1000) else Message(nil, "Watchdog instance manual launch") -- Call Check function Check(nil) end . Le paramétrage du script s'effectue dans les quelques lignes situées sous le commentaire "User variables" : intervalle : durée entre 2 vérifications delay : délai avant la première vérification. En effet, cette scène ayant la propriété autostart afin de démarrer automatiquement au boot de la box, le risque est de démarrer avant les autres Scène/VD, et de forcer un redémarrage de ceux-ci alors qu'ils n'ont pas encore effectivement démarré. Ce délai laisse donc aux autres Scène/VD le temps de démarrer et de s'initialiser proprement. watchdog : tableau dont chaque ligne représente une Scène ou un Virtual Device à monitorer : type : "Scene" ou "VD" id : valeur numérique représentant l'ID de la Scène ou VD à monitorer match : texte qui doit être trouvé pendant un certain laps de temps afin de confirmer le bon fonctionnement du VD/Scène. Cela correspond typiquement à un message affiché cycliquement à intervalle régulier. Les 2 champs suivants doivent être renseignés pour que la condition soit prise en compte (condition ET) : text : chaine de caractères à trouver interval : durée en secondes no_match : texte qui ne doit pas être trouvé, sous peine de considérer le VD/Scène comme planté. Cela correspond typiquement à un message d'erreur LUA qui entraine le plantage du script. A noter que la condition no_match à priorité sur la condition match, c'est à dire que si le texte recherché par no_match est détecté, le VD/Scène sera redémarrer même si le texte recherché par match a été détecté. L'un ou l'autre des 2 champs suivants peuvent être renseignés pour que la condition soit prise en compte (condition OU) : text : chaine de caractères à trouver type : "ERROR" correspond aux messages affichés en rouge dans la fenêtre de Debug de l'interface HC2. A noter que jusqu'en v4.056, dans une scène une erreur LUA affichait le message en rouge avec le type "ERROR", tandis que depuis les Beta v4.057 et v4.058, cette même erreur s'affiche en blanc sans le type ERROR, par conséquent ce test ne fonctionne plus. En revanche, aucun changement de mode de fonctionnement concernant les Virtual Devices. count : valeur valable pour les scènes uniquement, et indiquant le nombre minimal d'instances qui doivent fonctionner pour confirmer le bon fonctionnement de la scène. Cela correspond typiquement à l'instance de type boucle infinie lancée en autostart. restart : true ou false afin de redémarrer le VD/Scène concerné, ou seulement envoyer une notification signalant qu'il faut le redémarrer manuellement. notification : liste séparée par des virgules des moyens de notifications à employer. userID : liste séparée par des virgules des ID des utilisateurs qui doivent recevoir des notifications par email (le mail est celui configuré pour chaque utilisateur dans le panneau de contrôle d'accès) smartphoneID : liste séparée par des virgules des ID des smartphones qui doivent recevoir des notifications push (à récupérer dans le toolkit de Krikroff ou via l'API : /api/iosDevices) sms : si vous avez une passerelle SMS sous Android avec SMS Gateway (ou équivalent) pilotée par un module virtuel, il faut renseigner ici les informations nécessaires : VD_ID : ID du module virtuel VD_Button : ID du bouton du module virtuel VG_Name : nom de la variable globale debug : true ou false afin d'activer l'affichage étendu dans la fenêtre de débugage de la scène. Exemple de paramètres : -- User variables local intervalle = 60 local delay = 15*60 local watchdog = { {type = "Scene", id = 1, match = {text="", interval=0}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- Présence Lazer {type = "Scene", id = 2, match = {text="Last run", interval=2*60}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- DomoCharts {type = "Scene", id = 3, match = {text="Durée des traitements", interval=11*60}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- GEA {type = "VD", id = 1, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Surveillance Station {type = "VD", id = 2, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Clock Sync {type = "VD", id = 3, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- My Batteries {type = "VD", id = 4, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Evénements {type = "VD", id = 5, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Network Monitor {type = "VD", id = 6, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- GEA Alarm {type = "VD", id = 7, match = {text=" ", interval=30}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Sonos Player (Tk.isTraceEnabled = true) {type = "VD", id = 8, match = {text="Start main process", interval=31*60}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}} -- Freebox Serveur } local userID = {1} -- Email local smartphoneID = {1, 2} -- Push local sms = { ["VD_ID"] = 99, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local debug = false
  16. Utilisation de fibaro:call en fonction du module commandé Voici un lien qui vous donnera les actions que l'on peut utiliser pour chaque type de modules fibaro http://www.fibarouk.co.uk/support/lua/actions-use-fibarocall-api/ armed close firmwareUpdate open pollingDeadDevice pollingTimeSec pressButton requestNodeNeighborUpdate resetMeter sendDefinedEmailNotification sendDefinedPushNotification sendDefinedSMSNotification sendEmail sendGlobalEmailNotifications sendGlobalPushNotifications sendGlobalSMSNotifications sendPhotoToEmail sendPhotoToUser sendPush sendSipUserID setArmed setB setColor setG setProperty setProtectionLocalAndRF setR setSipDisplayName setSipUserID setSipUserPassword setSlider setTargetLevel setTime setValue setValue2 setW startProgram stop turnOff turnOn close Application pour : blind Description: Closes a blind. Usage: This action takes no arguments. Exemple: -- Close the blind with the device ID of 94 fibaro:call(94, "close") open Application pour : blind Description: Opens a blind. Usage: This action takes no arguments. Exemple: -- Open the blind with the device ID of 94 fibaro:call(94, "open") pressButton Application pour : virtual_device Description: Triggers a virtual device button press. Usage: This action takes one argument. The number of the button to be pressed. Each element of a virtual device has a unique number starting from 1. If your virtual device has two labels followed by two buttons, the buttons will be numbered 3 and 4. Exemple: -- Trigger a button press of button 3 of -- the virtual device with an ID of 358 fibaro:call(358, "pressButton", "3") sendDefinedEmailNotification Application pour : HC_user Description: Sends a notification to the email address associated with a user. Usage: This action takes one argument. The id of the notification to be sent. Exemple: 1-- Send notification 2 via email to the -- address associated with user 107. fibaro:call(107, "sendDefinedEmailNotification", "2") sendDefinedPushNotification Application pour : iOS_device Description: Sends a push notification to a device. Usage: This action takes one argument. The id of the notification to be sent. Exemple: -- Send notification 2 via push to modile device number 10. fibaro:call(10, "sendDefinedPushNotification", "2") sendDefinedSMSNotification Application pour : HC_user Description: Sends an SMS notification to a phone number. Usage: This action takes two arguments. The phone number to send the message to.This should be in the form xxyyyyyyyyy where xx = country code and yyyyyyyyy = phone number. The id of the notification to be sent. Exemple: -- Send notification 3 via SMS to device number +441234567890. fibaro:call(2, "sendDefinedSMSNotification", "441234567890", "3") sendEmail Application pour : HC_user Description: Sends an email to the email address associated with a user. Usage: This action takes two arguments. The subject of the email. The message body of the email. Exemple: -- Send an email to the email address associated with user 2. local subject = "This is the subject of the email." local message = "This is the body of the email.\nWith a line break." fibaro:call(2, "sendEmail", subject, message) sendPhotoToEmail Application pour : IP_camera Description: Sends a still image from a camera to a specified email address. Usage: This action takes one argument. The email address to send the image to. Exemple: -- Send an image from camera 120 to someone@this.address. fibaro:call(120, "sendPhotoToEmail", "someone@this.address") sendPhotoToUser Application pour : IP_camera Description: Sends a still image from a camera to the email address associated with a user. Usage: This action takes one argument. The id number of the user to send the image to. Exemple: -- Send an image from camera 120 to -- the email address associated with user 2. fibaro:call(120, "sendPhotoToUser", "2") sendPush Application pour : iOS_device Description: Sends a push notification to an iOS device. The device must have connected with the Home Centre recently, however once this connection has been made the app can be closed. Usage: This action takes one argument. The message to be pushed to the device. Exemple: -- Send a push notification to the iOS device with the ID of 10 fibaro:call(10, 'sendPush', 'This is the message to be pushed.') setArmed Application pour : motion_sensor, door_sensor, window_sensor, smoke_sensor Description: Arms or disarms a device. Usage: This action takes one argument. The armed state of the device. 0 = disarmed, 1 = armed. Exemple: -- Arm the door sensor with device ID of 174 fibaro:call(174, "setArmed", "1") -- Disarm the door sensor with device ID of 174 fibaro:call(174, "setArmed", "0") setB Application pour : rgb_driver Description: Sets the brightness of the blue channel of an rgb_driver. Usage: This action takes one argument. The brightness (0-99) of the channel. Exemple: -- Set the brightness of the blue channel of device 81 to 56% fibaro:call(81, "setB", "56") setColor Application pour : rgb_driver Description: Sets the colour of an rgb_driver. This is done by setting the brightness of the red, green, blue and white channels. Usage: This action takes four arguments. The brightness (0-99) of the red channel. The brightness (0-99) of the green channel. The brightness (0-99) of the blue channel. The brightness (0-99) of the white channel. Even if the device is in RGB mode, the white channel needs to be specified – in this case, just use 0. Exemple: -- Set the colour of device 81 to a blue-indigo colour -- (60% red, 23% green, 99% blue, 0% white) fibaro:call(81, "setColor", "60", "23", "99", "0") setG Application pour : rgb_driver Description: Sets the brightness of the green channel of an rgb_driver. Usage: This action takes one argument. The brightness (0-99) of the channel. Exemple: -- Set the brightness of the green channel of device 81 to 56% fibaro:call(81, "setG", "56") setProperty Application pour : virtual_device Description: Sets value of the elements of a virtual device (labels and sliders). Usage: This action takes two arguments. The name of the element. The value to set the element to. Exemple: -- Set the content of Label1 in virtual device 1170 to 'program 1' fibaro:call(1170, "setProperty", "ui.Label1.value", "program 1") -- Set the value of Slider1 in virtual device 1170 to 45 fibaro:call(1170, "setProperty", "ui.Slider1.value", "45") setR Application pour : rgb_driver Description: Sets the brightness of the red channel of an rgb_driver. Usage: This action takes one argument. The brightness (0-99) of the channel. Exemple: -- Set the brightness of the red channel of device 81 to 56% fibaro:call(81, "setR", "56") setSlider Application pour : virtual_device Description: Triggers a change in the value of a virtual device slider. Usage: This action takes two arguments. The number of the slider to be changed. Each element of a virtual device has a unique number starting from 1. If your virtual device has two labels followed by two buttons and then a slider, the slider will be numbered 5. The value (0-99) to set the slider to. Exemple: -- Set the slider with an ID of 2 of the -- virtual device with an ID of 334 to 50% fibaro:call(334, "setSlider", "2", "50") setTargetLevel Application pour : thermostat_setpoint Description: Sets the target temperature of a thermostat_setpoint. Usage: This action takes one argument. A temperature in degrees. Exemple: -- Set the target temperature of device 117 to 18 degrees. fibaro:call(117, "setTargetLevel", "18") setTime Application pour : thermostat_setpoint Description: Sets the value of the timeStamp property of the thermostat_setpoint. Usage: This action takes one argument. A timestamp. Exemple: -- Set the timeStamp of the thermostat_setpoint -- with device ID of 117 to 2 hours from now. fibaro:call(117, "setTime", tonumber(os.time()) + 120*60) setValue Application pour : dimmable_light, blind, rgb_driver Description: Sets the brightness of a dimmable_light or rgb_driver or sets the position of a blind. When changing the brightness of rgb_drivers, all channels are set to the same level (white light). Usage: This action takes one argument. A value (0-99) representing the brightness of the light or position of the blind. For a blind, 0 = fully closed, 99 = fully open. Exemple: -- Set the brightness of the light with device ID of 68 to 25%. fibaro:call(68, "setvalue", "25") -- Set the position of the blind with the device ID of 94 to 75% open. fibaro:call(94, "setvalue", "75") setW Application pour : rgb_driver Description: Sets the brightness of the white channel of an rgb_driver. Usage: This action takes one argument. The brightness (0-99) of the channel. Exemple: -- Set the brightness of the white channel of device 81 to 56% fibaro:call(81, "setW", "56") startProgram Application pour : rgb_driver Description: Instruct the rgb_driver to play one of the preconfigured colour programmes. Usage: This action takes one argument. The light programme number to run. Exemple: -- Start programme number 2 ("storm") on device number 81 fibaro:call(81, "startProgram", "2") stop Application pour : blind Description: Stops the movement of a blind. Usage: This action takes no arguments. Exemple: -- Stop the blind with the device ID of 94 fibaro:call(94, "stop") turnOff Application pour : binary_light, dimmable_light, rgb_driver Description: Turns off a device. Usage: This action takes no arguments. Exemple: -- Turn off device number 58. fibaro:call(58, "turnOff") turnOn Application pour : binary_light, dimmable_light, rgb_driver Description: Turns on a device. Usage: This action takes no arguments. Exemple: -- Turn on device number 58. fibaro:call(58, "turnOn")
  17. Lazer

    Network Monitor

    Network Monitor Version 1.20 Voici un module virtuel permettant de surveiller plusieurs équipements sur le réseau local (et aussi sur Internet), et d'envoyer des notifications en cas de problème détecté. Icônes : Je propose ces 2 icônes, mais d'autres icônes sont disponibles dans les pages du topic : Configuration : Après import du module virtuel, modifier la section "User Variables" du 1er bouton du module virtuel : -- User variables local userID = {5} -- Mail local smartphoneID = {73, 127} -- Push local sms = { ["VD_ID"] = 98, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local icons = { ["OK"] = 1028, -- Normal Icon ID ["Error"] = 1045 -- Error Icon ID } local DEVICES = { -- ["Service Name"] = { IP Address , Port, Protocol, Data to send, Expected return code, Expected data, Retry, {Notification methods}, VG, VG }, ["Eco-Devices"] = {"192.168.1.1", 80, "http", "/index1.htm", 200, "Eco Devices" , 1, {"push", "email", "sms"}, nil, nil}, ["HP ProLiant Remote Access Card"] = {"192.168.1.2", 80, "http", "/login.html", 200, "Remote Access Card" , 1, { "email" }, nil, {"Vacances", "1"}}, ["HP ProLiant Gen8 ILO"] = {"192.168.1.3", 443, "tcp", "", nil, "" , 1, { "email" }, nil, nil}, ["ESXi"] = {"192.168.1.4", 80, "http", "/", 301, "" , 1, {"push", "email", "sms"}, nil, nil}, ["Synology DiskStation"] = {"192.168.1.5", 5000, "http", "/webman/index.cgi", 200, "DiskStation" , 1, {"push", "email", "sms"}, nil, nil}, ["Raspberry PI"] = {"192.168.1.6", 80, "http", "/", 200, "Welcome to nginx" , 1, {"push", "email", "sms"}, nil, nil}, ["Sonos"] = {"192.168.1.7", 1400, "http", "/status", 200, "Options" , 1, {"push", "email" }, nil, {"Vacances", "1"}}, ["SMS Gateway"] = {"192.168.1.8", 9090, "http", "/", 200, "Welcome to SMS Gateway" , 5, {"push", "email" }, nil, nil}, ["VRT-IP"] = {"192.168.1.9", 80, "http", "/", 200, "Volets Roulant de Toit" , 1, {"push", "email" }, nil, nil}, ["IPX800"] = {"192.168.1.10", 80, "http", "/user/index2.htm", 200, "IPX800" , 1, {"push", "email" }, nil, nil}, ["Foscam"] = {"192.168.1.11", 88, "http", "/", 200, "IPCam Client" , 1, {"push", "email", "sms"}, nil, {"Vacances", "0"}}, ["Hikvision"] = {"192.168.1.12", 80, "http", "/doc/page/login.asp", 200, "login" , 1, {"push", "email", "sms"}, nil, nil}, ["HAproxy"] = {"192.168.1.13", 80, "http", "/", 503, "" , 1, {"push", "email", "sms"}, nil, nil}, ["FHEM"] = {"192.168.1.14", 8083, "http", "/fhem", 200, "EnOcean" , 1, {"push", "email", "sms"}, nil, nil}, ["Freebox"] = {"192.168.1.15", 80, "http", "/login.php", 200, "Freebox OS" , 1, { "sms"}, nil, nil}, ["OpenVPN"] = {"192.168.1.16", 443, "tcp", "", nil, "" , 1, { "email", "sms"}, nil, nil}, ["Redhat"] = {"192.168.1.17", 22, "tcp", nil, nil, "OpenSSH" , 1, { "email" }, nil, nil}, ["Google"] = {"www.google.fr", 80, "http", "/", 200, "Recherche Google" , 1, { "sms"}, nil, nil}} } local debug = false userID : liste séparée par des virgules des ID des utilisateurs qui doivent recevoir des notification par email (le mail est celui configuré pour chaque utilisateur dans le panneau de contrôle d'accès) smartphoneID : liste séparée par des virgules des ID des smartphones qui doivent recevoir des notifications push (à récupérer dans le toolkit de Krikroff ou via l'API : /api/iosDevices) sms : si vous avez une passerelle SMS sous Android avec SMS Gateway (ou équivalent) pilotée par un module virtuel, il faut renseigner ici les informations nécessaires. icons : si vous avez 2 icônes personnalisées, remplacer les valeurs nil par les ID numériques de vos icones (à trouver dans /api/icons) DEVICES : c'est la partie la plus longue à paramétrer, pour cela je vous ai laissé un exemple de tout ce que je monitore chez moi (j'ai juste changé les IP). C'est assez parlant, vous pouvez copier/coller en respectant bien la syntaxe. A noter que si l'avant-dernière colonne qui contient le nom facultatif d'une variable globale à incrémenter, celle-ci est automatiquement créée par le module. La dernière colonne permet d'annuler le monitoring d'un équipement particulier en fonction de la valeur d'une variable globale. debug : true ou false afin d'activer l'affichage étendu dans la fenêtre de débugage du bouton du module virtuel. Dans la Main Loop, le code est de Steven. Il y a une variable nbHeure permettant de paramétrer l'intervalle de vérification, par défaut à 1 heure. Si vous voulez un rafraichissement inférieur à 40 minutes, il suffit de tout remplacer par un simple fibaro:sleep(), car cette fonction ne plante pas pour les durées inférieures. Network_Monitor_v1.01.vfib Network_Monitor_v1.10.vfib Network_Monitor_v1.20.vfib
  18. Steven

    Evénements

    Evénements Module virtuel pour afficher les derniers événements Lorsque l'on fait des tests, il est parfois pratique d'avoir la liste des derniers événements ayant eu lieu sur notre HC2. Voici donc mon dernier module virtuel avant les vacances :-) Comme vous pouvez le voir, ce module affiche les 10 événements en oubliant volontairement les modules de températures. Si vous voulez voir plus d'événements, il vous faudra rajouter vous-même des labels en faisant juste attention que leur ID suivent la numérotation Label11, Label12, Label13, ... et modifier la position du bouton rafraîchir dans le Main Loop. J'ai volontairement ajouté la pièce pour certaine personne qui se reconnaîtrons Ce dernier affiche donc : Le nom du module concerné La pièce dans laquelle il se trouve Son ancienne valeur Sa nouvelle valeur L'heure de l'événement Ce module se rafraîchi automatiquement toutes les 3 secondes . . . Installation Il vous suffit juste d'importer le module virtuel ci-joint puis de modifier votre pseudonyme et mot de passe qui se trouve dans le bouton Rafraichir local user = "admin" local pwd = "password" HC2 = Net.FHttp("127.0.0.1",80) HC2:setBasicAuthentication(user, pwd) ... Cordialement Evenements.vfib
  19. Voici un périphérique virtuel qui a pour utilité de détecter et de notifier un utilisateur lorsqu’une nouvelle mise à jour est disponible en téléchargement pour le HC2 de Fibaro. (Publié sur le blog de Pascal le 21-03-2014) Version 1.0.8 - Mise à jour : 13/01/2015 Vous pouvez télécharger la dernière version ici et sur le blog consulter la notice d'installation et d'utilisation bien que tout soit simplifié au maximum Version 1.0.8 - Mise à jour : 13/01/2015 (Pour HC2 >= V4.031) Aucunes configuration nécessaire dorénavant, il faut importer le vd et c'est tout. Compatible API REST de la V4 L'unique paramétrage restant à faire par l'utilisateur est de préciser dans le code (dans le mainloop) l' ID du smartphone et de l' utilisateur pour les notifications. local userID = 2; local smartphoneID = 844; Version 1.0.6 - Mise à jour : 08/09/2014 (Pour HC2 <= V3.600) L'image principale du Virtual Device réapparaît maintenant automatiquement après l'appui sur un bouton Notification de mise à jour disponible sur la home du périphérique virtual. Remise en forme et révision du code Version 1.0.5 - Mise à jour : 04/09/2014 Amélioration: Récupération automatique de la variable en cas de données corrompues (suggéré par Lazer) Mise à jour des traductions Version 1.0.4 - Mise à jour : 03/09/2014 Nouveau: Affichage du numéro de version dans l'interface utilisateur et ajouté à la notification (mail & push) Nouveau: Icône d'un membre du forum domotique-fibaro.fr, merci Lazer Amélioration: Envoyer une notification si une nouvelle mise à jour est détectée et ne pas répéter les envois. Corrections mineures. Version 1.0.2 - Mise à jour : 21/02/2014 Corrections mineures. Version 1.0.1 - Mise à jour : 14/02/2014 Installation automatisée pour faciliter la mise en place des variables globales et du paramétrage de l’application. Possibilité de choisir le type de notification avec un bouton à trois états depuis l’interface graphique: Email, Push ou les deux. Possibilité de choisir le type de mise à jour devant être notifié avec un bouton à trois états depuis l’interface graphique : Bêta, stable ou les deux. Multilingue : Français, Anglais. Téléchargements: UpdateNotifier_1.0.8.zip pour HC2 en V4.xxx
  20. sebcbien

    Detection De Présence

    Bonjour, Suite à une conversation en MP avec un de nos admin chéri ;-), voici ma solution pour détecter la présence via smartphone. L'idée est de savoir quand ma femme ou moi même sommes à la maison afin de pouvoir lancer des scénarios ou en bloquer l’exécution. J'ai fait ça il y a longtemps, et bien sur je n'ai pas tout fait tout seul. Je me souviens avoir fait quelques modifications pour que ça tourne comme je le voulais, mais je ne sais plus lesquelles. Bref, voici le package complet, pour certains scripts, comme pour le ping par exemple la base est de Krikroff et j'ai laissé le copyright. J'ai mis le Virtual Device en attach et le code du bouton ci-dessous . IP Smartphone Presence Check V1.0.vfib !!! voir post plus loin dans le fil pour les V1.1 V1.2 V1.3 V2.0 et suivantes !!! V2.1 ici: https://www.domotique-fibaro.fr/topic/2613-detection-de-prã©sence/?do=findComment&comment=121355 V1.3 ici: http://www.domotique-fibaro.fr/index.php/topic/2613-detection-de-pr%C3%A9sence/page-3#entry35219 - il faut créer une variable globale (non prédéfinie) par device à surveiller (moi j'utilise "Phone_GG_Present" pour le tel de ma femme) et la déclarer en début de script du bouton. - il faut encoder l'adresse IP du téléphone dans les paramètres du Virtual device (pensez à déterminer une ip Wifi fixe pour votre smartphone) - il faut encoder le port ouvert sur votre téléphone dans les paramètres du Virtual device (3500 ou 3401) - Sur Androà¯d, il n'y a pas de port ouvert par défaut pour accepter le ping, le moyen le plus simple est d'installer l'application Sonos et a lancer, c'est tout (pas besoin d'avoir du matos sonos pour que ça fonctionne) - Sur iPhone idem, mais je n'ai pas testé personellement - si vous ne voulez pas utiliser le mainloop comme "scheduler" , créez simplement une scène qui va cliquer sur le bouton de demande de présence toutes les minutes... ou avec l'excellent GEA, avec la ligne ci-dessous (à adapter): -- Mise à jour des Présences par détection d'adresses IP toutes les minutes GEA.add(true , 1*60, "",{{"VirtualDevice", id["VD_PRESENCE_SEB"], "1"},{"VirtualDevice", id["VD_PRESENCE_GG"], "1"},{"Repeat"}}) Notification de présence en utilisant GEA, entre 8h et 21h: N'oubliez pas de mettre les VG dans l'entête. Ces exemple sont repris dans le post GEA de ma signature --------------DETECTION PRESENCE-------------- -- Signale GG at Home GEA peux se déclencher sur un changement de valeur d'une variable global GEA.add({"Global", "Phone_GG_Present", "1"}, -1, "Presence GG est maintenant à #value#", {{"Portable", 53}, {"Time", "08:00", "21:00"}}) GEA.add({"Global", "Phone_GG_Present", "0"}, -1, "Presence GG est maintenant à #value#", {{"Portable", 53}, {"Time", "08:00", "21:00"}}) Code bouton VD détect presence V1.0 (ancien code): -- IP Smartphone Presence Check V1.0 -- Copyright © 2014 Sébastien Jauquet. -- http://www.domotique-fibaro.fr/index.php/topic/2613-detection-de-pr%C3%A9sence/ --Using code from: -- Ping v 1.0.1 [05-2013] -- Copyright © 2013 Jean-christophe Vermandé -- http://www.domotique-fibaro.fr/index.php/topic/109-ping-dun-%C3%A9quipement-r%C3%A9seau/page-2 fibaro:log("Starting process"); local _deviceIp = "192.168.10.112"; local variable_globale_phone = "Phone_GG_Present"; local _devicePort = 3500; local _maxRetryProcess = 20; local time = tonumber(os.time()); local maxtime = 56; -- fibaro:setGlobal("Lock_Away","Unlocked") function SecondsToClock(sSeconds) local nSeconds = tonumber(sSeconds) if nSeconds == 0 then return "00:00:00"; else nHours = string.format("%02.f", math.floor(nSeconds/3600)); nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); return nHours..":"..nMins..":"..nSecs end end -- recursive function to ping device local function _ping(retry) retry = retry or 0; -- notify state local elapsed = os.difftime(os.time(), tonumber(time)); local msg = "Loop #".. retry .." since "..SecondsToClock(elapsed); fibaro:log(msg); -- check for no more than 30 seconds if elapsed > maxtime then return false; end --open the socket local tcpSocket = Net.FTcpSocket(_deviceIp, _devicePort); --set the read timeout tcpSocket:setReadTimeout(250); --send packet local bytes, errorCode = tcpSocket:write("test"); --check for error if errorCode == 0 then return true; else if retry < _maxRetryProcess then --fibaro:log("Retry process, please wait..."); fibaro:sleep(1*750); return _ping(retry + 1); end return false; end end --ping device, secure with pcall to catch errors. local f, result = pcall(_ping); local Lock_Away = fibaro:getGlobal("Lock_Away") if (f) then if (result == true) and (Lock_Away == "Unlocked") then fibaro:log("Device has been found."); fibaro:setGlobal(variable_globale_phone,"1") -- fibaro:setGlobal("Present_Phones",os.time()) else fibaro:log("Device was not found!"); fibaro:setGlobal(variable_globale_phone,"0") end else fibaro:log("Error: " .. f); end Code main loop du VD local thismodule = fibaro:getSelfId(); local status = fibaro:getGlobal("Phone_GG_Present") -- fibaro:debug(thismodule); if status == "0" then fibaro:call(thismodule, "setProperty", "currentIcon", 1037) end if status == "1" then fibaro:call(thismodule, "setProperty", "currentIcon", 1036) end fibaro:sleep(1000); Ce n'est certainement pas le code le plus "léché" mais je pense que ça en aidera quand même certains... et puis c'est "tout fait" ;-) Le script va détecter quasi instantanément lorsque le smartphone apparaît sur le réseau, mais pourra mettra jusqu'à une minute pour valider son absence Enjoy !
  21. Krikroff

    Hc2 Waze Calculator

    Après longue absence voici un petit script permettant d’utiliser sur notre HC2 le service de trafic et de navigation communautaire WAZE (https://www.waze.com/fr/) Le principe du script est très simple : 1 scène pour interroger l’ API Waze pour tous les trajets parametrés et autant de vd qui seront mis à jour par la dite scène.] 1 - Installation Importer le vd HC2_Waze_Calculator.vfib sur le HC2, 1x pour un trajet, 2x pour deux etc... Créer la scène HC2 Waze Calculator cf. fichier HC2 Waze Calculator Scene.txt puis passer au paramètrage 2 - Paramétrage Configurer l'object params: nom, id du vd cible, polling, latitude, longiture etc... pour tous les trajets. Pour trouver les coordonnées GPS, latitude et longitude il existe les services : www.coordonnees-gps.fr, www.torop.net/coordonnees-gps.php, www.gpsfrance.net etc. local params = { { name = "Trajet 1", virtualDeviceId = 1449, from = { name = "Palais de l'Élysée", x = 2.3167538999999806, -- longitude y = 48.8704156 -- latitude }, to = { name = "Théâtre Guignol", x = 2.311747670173645, -- longitude y = 48.86977710077997 -- latitude }, pollingMs = 60*1000 }, { name = "Trajet 2", virtualDeviceId = 1452, from = { name = "Palais de l'Élysée", x = 2.3167538999999806, -- longitude y = 48.8704156 -- latitude }, to = { name = "Théâtre Guignol", x = 2.311747670173645, -- longitude y = 48.86977710077997 -- latitude }, pollingMs = 5*60*1000 } } 4 - Icône Merci à Moicphil de m’avoir suggéré la chose et aussi pour son icône tip-top Fichier du vd: HC2_Waze_Calculator.vfib Fichier de la scène: HC2 Waze Calculator Scene.txt
  22. Suite à un besoin particulier je voulais m'assurer de la taille maximale d'une variable globale afin de persister des informations de type chaînes de caractères si vous souhaitez faire l’expérience vous même, il faut créer une variable globale, ici: varMaxLength, puis dans un périphérique virtuel ajouter le code suivant dans un bouton for i=1, 250 do fibaro:setGlobal("varMaxLength", fibaro:getGlobalValue("varMaxLength").."0"); fibaro:debug("global variable length is now "..string.len(fibaro:getGlobalValue("varMaxLength"))); end pour remettre la variable à zero, dans un autre bouton le code suivante: fibaro:setGlobal("varMaxLength", ""); 228 est donc la taille maximale d'une chaîne dans une variable globale
  23. Bonjour, Voilà , le code est enfin correct, je le partage donc. Je n'ai pas beaucoup de temps ce soir, mais voici 2-3 points: - Ce VD crée automagiquement 3 Variables globales (si demandé dans les options) - Ce VD est multilingue - Ce VD fait des push de la météo à deux moments de la journée - CE VD s'adapte aux mobiles et à l'interface web - Ce VD télécharge automagiquement les icônes - Ce VD a besoin d'une clef APi de Wunderground, - La partie mobile du VD n'est pas encore complètement terminée. Merci à Jompa68 de forum.fibaro.com pour le code de base Pour l'installer: - Téléchargez le vfib attaché et importez le dans la HC2 - Changer l'icône du slider avec l'icône attachée: - Utilisez le dernier code disponible sur github: https://github.com/sjauquet/YAMSWU Qui ajoute la création de VG qui contiendront la météo prononçable par une synthèse vocale comme S.A.R.A.H.: http://www.domotique-fibaro.fr/index.php/topic/6446-yams-wu-yet-another-meteo-station-wunderground-version/page-4#entry132933 et placez-le dans le main loop du VFIB (V3.9) attaché à ce message - Changez l'api key. Pour cela, créez un compte wunderground et allez la récupérer ici: http://www.wunderground.com/weather/api/ WU.APIkey = "xxxxxxxxxxxxxxx" - Ensuite définissez les variables suivantes: WU.PWS = "IGVLEBOR5" -- The PWS location to get data from (Personal Weather Station) WU.LOCID = "SWXX0076" -- The location ID to get data from (City location) WU.station = "PWS" -- Choose your prefered method to retrieve from: PWS or LOCID Personnellement je préfère utiliser les infos d'une pws près de chez moi. Pour trouver ces variables: @bono2007 écrivait: Pour trouver, j'ai eu la station PWS en cliquant dans "Search locations" sur Wunderground, on te propose "search nearest station", et il a proposé une station météo proche. Sinon en entrant ta ville, tu peux cliquer sur "change Station" et tu verras une carte avec d'autres stations météo. Exemple : j'ai entré "Boussois" et j'ai comme station météo "Cit du Grand Bois, Récquignies ( IRECQUIG2) J'ai modifié WU.PWS = "IRECQUIG2" Et tout devrait fonctionner :-) Virtual device avec code V3.7 (ancien à remplacer !!! ) YAMS_WU.vfib Virtual device avec code V3.9 YAMS_WU V3.9.vfib Voici les dernières captures d'écran pour avoir une idée: à gauche en mode Browser Web, à droite en mode Mobile (les icônes ne sont pas téléchargeables) Attention, ancien code ci-dessous ! ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- -- WU WeatherData - Fetch weather data from wunderground.com. Multilanguage support! -- Original Code by Jonny Larsson 2015 http://forum.fibaro.com/index.php?/topic/19810-wu-weatherdata-version-202-2015-10-25/ -- forked by Sébastien Jauquet 11/2015 -- Inspired by GEA(steven), stevenvd, Krikroff and many other users. -- Source - forum.fibaro.com, domotique-fibaro.fr and worldwideweb -- -- Version 3.7 -- -- PWS = Personal Weather Station -- LOCID = Public station -- -- 2014-03-22 - Permissions granted from Krikroff -- 2014-03-23 - Added rain and forecast, Added FR language. -- 2014-03-23 - Language variable changed to get the translation from wunderground.com in forcast -- 2014-03-24 - Added PL language -- 2014-03-24 - Select between PWS or LOCID to download weather data -- 2015-10-23 - New source code. -- 2015-11-13 - V3.0 - Fork Code by Sebastien Jauquet (3 days forecast, rain in mm) -- 2015-11-14 - V3.1 - Compatibilty with GEA, French translation -- 2015-11-14 - V3.2 - Catch rain errors (-999mm null empty etc.) -- 2015-11-14 - V3.3 - Catch json decode error (was stopping main loop) with pcall (can be extended to other jdon datas if needed) -- 2015-11-16 - V3.4 - Generate HTML and non HTML version (for compatibility with mobiles) -- 2015-11-18 - V3.5 - Fixed bug not updating Meteo_Day becaus WU.now was only updated at first launch -- 2015-11-18 - V3.6 - Merged some changes from jompa new version -- 2015-11-18 - Added autmatic creation of Global Variables if not existing -- 2015-11-19 - V3.7 - Modify schedule management and CleanUp code -- Look for nearest station here: http://www.wunderground.com ------------------------------------------------------------------------------------------- -- MAIN CODE -- ------------------------------------------------------------------------------------------- WU = {} -- WU settings WU.APIkey = "xxxxxxxxxxxxxxx" -- Put your WU api key here WU.PWS = "IGVLEBOR5" -- The PWS location to get data for (Personal Weather Station) WU.LOCID = "SWXX0076" -- The location ID to get data for (City location) WU.station = "PWS" -- PWS or LOCID -- Other settings WU.translation = {true} WU.language = "FR"; -- EN, FR, SW, PL (default is en) WU.smartphoneID = 1347 -- your smartphone ID WU.sendPush = true -- send forecast as push message WU.push_fcst1 = "07:00" -- time when forecast for today will be pushed to smartphone WU.push_fcst2 = "18:15" -- time when forecast for tonight will be pushed to smartphone WU.GEA = true -- subst % with %% when storing in the VG's (because gea bug with % in push messages) WU.CreateVG = true -- will atomaticaly create global variables at first run if = true updateEvery = 30 -- get data every xx minutes WU.startTime = os.time() WU.scheduler = os.time()+60*updateEvery WU.currentDate = os.date("*t"); WU.now = os.date("%H:%M"); DoNotRecheckBefore = os.time() WU.selfId = fibaro:getSelfId() WU.version = "3.7" WU.translation["EN"] = { Push_forecast = "Push forecast", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperature", Humidity = "Humidity", Pressure = "Pressure", Wind = "Wind", Rain = "Rain", Forecast = "Forecast", Station = "Station", Fetched = "Fetched", Data_processed = "Data processed", Update_interval = "Next update will be in (min)", No_data_fetched = "No data fetched", NO_STATIONID_FOUND = "No stationID found", NO_DATA_FOUND = "No data found" } WU.translation["FR"] = { Push_forecast = "Push des prévisions", Exiting_loop_slider = "Sortie de boucle (Slider Changé)", Exiting_loop_push = "Sortie de boucle (Pour Push)", Last_updated = "Mise à jour", Temperature = "Actuellement", Humidity = "Hum", Pressure = "Pression", Wind = "Vent", Rain = "Pluie", Forecast = "Prévisions pour ce", Station = "Station", Fetched = "Données Reçues", Data_processed = "Données mises à jour", Update_interval = "Prochaine Mise à jour prévue dans (min)", No_data_fetched = "Pas de données reçues !!", NO_STATIONID_FOUND = "StationID non trouvée !!", NO_DATA_FOUND = "Pas de données disponibles !!" } WU.translation["SW"] = { Push_forecast = "Push forecast", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatur", Humidity = "Fuktighet", Pressure = "Barometer", Wind = "Vind", Rain = "Regn", Forecast = "Prognos", Station = "Station", Fetched = "Hà¤mtat", Data_processed = "All data processat", Update_interval = "Nà¤sta uppdatering à¤r om (min)", No_data_fetched = "Inget data hà¤mtat", NO_STATIONID_FOUND = "StationID ej funnet", NO_DATA_FOUND = "Ingen data hos WU" } WU.translation["PL"] = { Push_forecast = "Push prognoza", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatura", Humidity = "Wilgotnosc", Pressure = "Pressure", Wind = "Wiatr", Rain = "Rain", Forecast = "Forecast", Station = "Station", Fetched = "Fetched", Data_processed = "Data processed", No_data_fetched = "No data fetched", Update_interval = "Next update will be in (min)", NO_STATIONID_FOUND = "No stationID found", NO_DATA_FOUND = "No data found" } WU.translation["NL"] = { Push_forecast = "Push verwachting", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatuur", Humidity = "Vochtigheid", Pressure = "Druk", Wind = "Wind", Rain = "Regen", Forecast = "Verwachting", Station = "Weerstation", Fetched = "Ontvangen", Data_processed = "Gegevens verwerkt", Update_interval = "Volgende update in (min)", No_data_fetched = "Geen gegevens ontvangen", NO_STATIONID_FOUND = "Geen stationID gevonden", NO_DATA_FOUND = "Geen gegevens gevonden" } WU.translation["DE"] = { Push_forecast = "Push vorhersage", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatur", Humidity = "Luftfeuchtigkeit", Pressure = "Luftdruck", Wind = "Wind", Rain = "Regen", Forecast = "Vorhersage", Station = "Station", Fetched = "Abgerufen", Data_processed = "Daten verarbeitet", No_data_fetched = "Keine Daten abgerufen", Update_interval = "Das nà¤chste Update in (min)", NO_STATIONID_FOUND = "Keine stationID gefunden", NO_DATA_FOUND = "Keine Daten gefunden" } Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, message, "span")); end WU.createGlobalIfNotExists = function (varName, defaultValue) if (fibaro:getGlobal(varName) == "") then Debug("red", "Global Var: "..varName.." HAS BEEN CREATED") newVar = {} newVar.name = varName HC2 = Net.FHttp("127.0.0.1", 11111) HC2:POST("/api/globalVariables", json.encode(newVar)) end end WU.substPercent = function(doublePercentSymbol) if WU.GEA then doublePercentSymbol = string.gsub(doublePercentSymbol, "%%.", "%%%%") end return doublePercentSymbol end WU.cleanJson = function(jsontocheck,returnIfTrue) if jsontocheck == "-999.00" or jsontocheck == "--" or jsontocheck == json.null then jsontocheck = returnIfTrue end local ok = pcall(function() testConcatenate = "Test Concatenate: " .. jsontocheck -- test for non concatenate value end ) if (not ok) then decode_error = true Debug( "red", "decode raised an error") fibaro:call(WU.smartphoneID , "sendPush", "decode error in WU Meteo") end return jsontocheck end WU.HtmlColor = function(StringToColor,color) if MobileDisplay == false then StringToColor= "<font color=\""..color.."\"> "..StringToColor.."</font>" end return StringToColor end WU.IconOrText = function(icon,txt) if MobileDisplay == false then IconOrText = "<img src="..icon.."\>" else IconOrText = txt end return IconOrText end WU.getSlider = function() ValeurSliderfunct = fibaro:getValue(WU.selfId , "ui.WebOrMobile.value") return tonumber(ValeurSliderfunct) end WU.setSlider = function(position) fibaro:call(WU.selfId , "setProperty", "ui.WebOrMobile.value", position) return WU.getSlider() end WU.checkMobileOrWeb = function() ValeurSliderSleep = WU.getSlider() -- check slider value at first run if ValeurSliderSleep <= 50 then if ValeurSliderSleep == 1 then MobileDisplay = false else MobileDisplay = false WU.runDirect = 1 sleepAndcheckslider = 20*updateEvery -- exit wait loop Debug("orange", WU.translation[WU.language]["Exiting_loop_slider"]); end WU.setSlider(1) -- désactive le run immediat lors du prochain test end if ValeurSliderSleep >= 50 then if ValeurSliderSleep == 98 then else MobileDisplay = true WU.runDirect = 1 sleepAndcheckslider = 20*updateEvery -- exit wait loop Debug("orange", WU.translation[WU.language]["Exiting_loop_slider"]); end WU.setSlider(98) -- désactive le run immediat lors du prochain test end return WU.getSlider() end WU.fetchWU = function() decode_error = false WU.checkMobileOrWeb() local WGROUND = Net.FHttp("api.wunderground.com",80); local response ,status, err = WGROUND:GET("/api/"..WU.APIkey.."/conditions/forecast/lang:"..WU.language.."/q/"..WU.station..":"..locationID..".json"); if (tonumber(status) == 200 and tonumber(err)==0) then Debug( "cyan", WU.translation[WU.language]["Fetched"]) if (response ~= nil) then WU.now = os.date("%H:%M") jsonTable = json.decode(response); if jsonTable.response.error ~= nil then Debug( "red", WU.translation[WU.language]["NO_DATA_FOUND"]) fibaro:sleep(15*1000) return end stationID = jsonTable.current_observation.station_id; humidity = jsonTable.current_observation.relative_humidity temperature = jsonTable.current_observation.temp_c pression = jsonTable.current_observation.pressure_mb wind = jsonTable.current_observation.wind_kph rain = WU.cleanJson(jsonTable.current_observation.precip_today_metric,"0") weathericon = jsonTable.current_observation.icon_url fcstday1 = jsonTable.forecast.txt_forecast.forecastday[1].title -- Day meteo fcst1 = jsonTable.forecast.txt_forecast.forecastday[1].fcttext_metric fcst1icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst1SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst1Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst1Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst1avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst1avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst1mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[1].qpf_day.mm,"0") fcstday2 = jsonTable.forecast.txt_forecast.forecastday[2].title -- Evening Meteo fcst2 = jsonTable.forecast.txt_forecast.forecastday[2].fcttext_metric fcst2icon = jsonTable.forecast.txt_forecast.forecastday[2].icon_url fcst2SmallTxt = jsonTable.forecast.simpleforecast.forecastday[2].conditions fcst2Tmax = jsonTable.forecast.simpleforecast.forecastday[2].high.celsius fcst2Tmin = jsonTable.forecast.simpleforecast.forecastday[2].low.celsius fcst2avewind =jsonTable.forecast.simpleforecast.forecastday[2].avewind.kph fcst2avewinddir =jsonTable.forecast.simpleforecast.forecastday[2].avewind.dir fcst2mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[1].qpf_night.mm,"0") fcstday3 = jsonTable.forecast.txt_forecast.forecastday[3].title -- Tomorrow fcst3 = jsonTable.forecast.txt_forecast.forecastday[3].fcttext_metric fcst3icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst3SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst3Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst3Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst3avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst3avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst3mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[2].qpf_allday.mm,"0") fcstday5 = jsonTable.forecast.txt_forecast.forecastday[5].title -- In 2 days fcst5 = jsonTable.forecast.txt_forecast.forecastday[5].fcttext_metric fcst5icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst5SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst5Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst5Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst5avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst5avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst5mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[3].qpf_allday.mm,"0") if (stationID ~= nil) and decode_error == false then fibaro:call(WU.selfId , "setProperty", "ui.lblStation.value", locationID); if temperature < 5 then cTemperature = WU.HtmlColor(temperature,"blue") elseif temperature > 18 then cTemperature = WU.HtmlColor(temperature,"red") else cTemperature = WU.HtmlColor(temperature,"yellow") end fibaro:call(WU.selfId , "setProperty", "ui.lblTempHum.value", WU.translation[WU.language]["Temperature"]..": "..cTemperature.." °C - "..WU.translation[WU.language]["Humidity"]..": "..humidity); fibaro:call(WU.selfId , "setProperty", "ui.lblWindRain.value", WU.translation[WU.language]["Wind"]..": "..wind.." km/h - "..WU.translation[WU.language]["Rain"]..": "..rain.." mm"); if (WU.now >= "00:00" and WU.now <= "15:59") then -- donne meteo du jour entre 00:00 (ou 3h) et 15:59. permet de garder la météo du soir jusqu'a 3h du matin, sinon change à minuit fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday1,"yellow")..": "..WU.HtmlColor(fcst1.." ("..fcst1mm.." mm)","green")); fibaro:setGlobal("Meteo_Day", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday1..": ".." "..fcst1.." ("..fcst1mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value",WU.IconOrText(fcst1icon,fcst1SmallTxt)); elseif (WU.now >= "16:00" and WU.now <= "23:59") then -- donne meteo soirée entre 16:00 et 23:59 fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday2,"yellow")..": "..WU.HtmlColor(fcst2.." ("..fcst2mm.." mm)","green")); fibaro:setGlobal("Meteo_Day", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday2..": ".." "..fcst2.." ("..fcst2mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value",WU.IconOrText(fcst2icon,fcst2SmallTxt)); end -- Meteo of Tomorrow fibaro:call(WU.selfId , "setProperty", "ui.lblFcstTomorrow.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday3,"yellow")..": "..WU.HtmlColor(fcst3.." ("..fcst3mm.." mm)","green")); fibaro:setGlobal("Meteo_Tomorrow", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday3..": ".." "..fcst3.." ("..fcst3mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIconTomorrow.value",WU.IconOrText(fcst3icon,fcst3SmallTxt)); -- Meteo in 2 Days fibaro:call(WU.selfId , "setProperty", "ui.lblFcst2Days.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday5,"yellow")..": "..WU.HtmlColor(fcst5.." ("..fcst5mm.." mm)","green")); fibaro:setGlobal("Meteo_In_2_Days", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday5..": ".." "..fcst5.." ("..fcst5mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon2Days.value",WU.IconOrText(fcst5icon,fcst5SmallTxt)); if WU.sendPush then if (os.date("%H:%M") == WU.push_fcst1) then -- fibaro:call(WU.smartphoneID , "sendPush", fcstday1.." - "..fcst1) -- envoie meteo du matin elseif (os.date("%H:%M") == WU.push_fcst2) then fibaro:call(WU.smartphoneID , "sendPush", fcstday2.." - "..fcst2) -- envoie meteo du soir end end if WU.sendPush then fibaro:call(WU.selfId , "setProperty", "ui.lblNotify.value", WU.translation[WU.language]["Push_forecast"].." = true"); else fibaro:call(WU.selfId , "setProperty", "ui.lblNotify.value",WU.translation[WU.language]["Push_forecast"].." = false"); end WU.scheduler = os.time()+updateEvery*60 fibaro:call(WU.selfId, "setProperty", "ui.lblUpdate.value", WU.translation[WU.language]["Last_updated"]..": "..os.date("%c")); Debug( "cyan", WU.translation[WU.language]["Data_processed"]) Debug( "white", WU.translation[WU.language]["Update_interval"].." "..updateEvery) else Debug( "red", WU.translation[WU.language]["NO_STATIONID_FOUND"]) end else fibaro:debug("status:" .. status .. ", errorCode:" .. errorCode); end end sleepAndcheckslider = 0 while sleepAndcheckslider <= 20*updateEvery do fibaro:sleep(3000) WU.checkMobileOrWeb() sleepAndcheckslider = sleepAndcheckslider+1 if (DoNotRecheckBefore <= os.time()) and ((WU.scheduler == os.time) or (os.date("%H:%M") == WU.push_fcst1) or (os.date("%H:%M") == WU.push_fcst2)) then Debug("orange", WU.translation[WU.language]["Exiting_loop_push"]); DoNotRecheckBefore = os.time()+60 sleepAndcheckslider = 20*updateEvery end end end Debug( "orange", "WU Weather - Original LUA Scripting by Jonny Larsson 2015"); Debug( "orange", "YAMS WU - Fork by Sébastien Jauquet 11/2015"); Debug( "orange", "Version: "..WU.version); if WU.station == "LOCID" then locationID = WU.LOCID elseif WU.station == "PWS" then locationID = WU.PWS end if WU.CreateVG then WU.createGlobalIfNotExists("Meteo_Day", "") WU.createGlobalIfNotExists("Meteo_Tomorrow", "") WU.createGlobalIfNotExists("Meteo_In_2_Days", "") end while true do WU.fetchWU() end
  24. Introduction : Suite à une discussion tenue il y a quelques temps dans le sujet Accès HC2 de l'extérieur, je propose un tutoriel sur le mise en Å“uvre d'un Reverse Proxy avec HAProxy sur un NAS Synology. Certes, c'est de l'informatique, et non pas de la domotique, mais le but principal est d'accéder à nos équipements domotiques (en particulier les box Fibaro Home Center 2 ou Home Center Lite) depuis l'extérieur. La discussion citée précédemment décrit différentes méthodes d'accès aux ressources du réseau local depuis Internet, notamment la technique du Port Forwarding, qui consiste à ouvrir un port TCP coté WAN pour chaque équipement interne à joindre. Cette méthode fonctionne bien si on se connecte à son HC2 depuis la connexion Internet d'un ami, depuis un hôtel, depuis le partage d'accès 3G/4G de son smartphone, ou depuis une entreprise qui ne filtre pas trop les connexions. Mais la plupart des entreprises mettent en place des proxy filtrants, qui ne laissent assez souvent passer que les ports 80 (HTTP) et 443 (HTTPS). Même les connexions FTP, VPN, SSH, etc... sont bloquées, donc forcément les ports personnalisés qu'on a choisi. Donc on doit mettre en place un Reverse Proxy. Sur Synology, on peut utiliser HAProxy, ou sinon on se créer son propre serveur Linux qui fera le boulot. Le principe de fonctionnement est simple : avec notre domaine DNS, on crée autant de sous-domaines qu'on souhaite joindre d'équipements dans notre LAN. Par exemple, dsm.domaine.com, hc2.domaine.com, ecodevice.domaine.com, etc... dans l'interface d'administration du routeur, on redirige le port TCP 80 externe vers le port 80 du NAS qui héberge HAProxy au sein du LAN. dans la configuration de HAProxy, on crée toutes les règles pour rediriger les sous-domaines vers la bonne adresse IP dans le LAN. Le schéma est donc le suivant : Utilisateur sur le WAN => Routeur ADSL => Reverse Proxy => Equipement final (HC2, ...) Glossaire simplifié des termes employés dans ce tutoriel : LAN = Local Area Network, désigne le réseau local domestique WAN = Wide Area Network, désigne Internet Routeur = équipement réseau assurant la communication entre le LAN et le WAN. En France, nous sommes majoritairement équipés de Box Internet prêtées par les fournisseurs d'accès à Internet, telles que Freebox, LiveBox, etc... Adresse IP = adresse sur 4 nombres (par exemple 192.168.1.1) permettant d'identifier un équipement sur le réseau, que ce soit le LAN ou le WAN. A noter que coté WAN, les adresses IP sont uniques sur tout Internet, tandis que coté LAN, on utilise des plages d'adresses dites "privées" (192.168.x.y, ou 172.16.x.y, ou 10.x.y.z) c'est à dire qu'elle ne sont pas visibles depuis Internet. Le routeur se charge d'effectuer de la translation d'adresse, si bien que lorsque nous surfons sur Internet, ce n'est pas l'adresse IP de notre ordinateur/téléphone/tablette qui est vue, mais l'adresse IP externe du routeur. Adresse IP fixe : l'adresse IP fournie par le fournisseur d'accès à Internet peut être fixe (notamment chez Free) ou variable, c'est à dire qu'elle sera différente à chaque nouvelle connexion (ou tranche de 24h, cela dépend). Les adresses IP fixes sont bien sà»r préférables pour pouvoir se connecter chez soit depuis l'extérieur, mais la méthode du DynDNS existe pour s'en sortir même avec une adresse IP variable. Nom de Domaine DNS : sur Internet, nous n'utilisons couramment pas les adresses IP, mais plutôt les noms de domaine, tels que google.com ou domotique-fibaro.fr. Pour chaque domaine, on peut créer pratiquement autant de sous-domaine que l'on souhaite, qui sont placés en préfixe du nom de domaine. Le plus célèbre d'entre eux est www, ce qui donne www.google.com ou www.domotique-fibaro.fr. Il est bien entendu possible de créer le sous-domaine de son choix, afin d'obtenir des adresses telles que hc2.mondomaine.com, ou ecodevices.mondomaine.fr, ... Limitations de ce tutoriel : Je me limite volontairement à l'utilisation du port 80 avec le protocole http non-sécurisé. En effet, si il pourrait paraitre tentant d'utiliser le protocole https sur le port 443, il faut savoir que nous n'avons qu'un certificat auto-signé, donc non reconnu par les navigateurs Web, et donc également par les proxy d'entreprises, qui peuvent rejeter la connexion pour les plus filtrants, par mesure de sécurité. Le but de mon tutoriel étant de passer au travers d'un maximum de proxy d'entreprise, cela a plus de chance de réussir en utilisant le port 80. Dans la pratique, tant que votre nom de domaine n'est pas blacklisté, cela devrait fonctionner. Si vraiment la sécurité est nécessaire, il faut acheter un certificat SSL et l'importer dans la configuration de HAProxy, ce qui sort du cadre de ce tutoriel. De plus, je tourne sous la version 4.3 de DSM, pour plusieurs raisons : C'est un version stable et en production chez moi Comme j'utilise Xpenology dans une machine virtuelle VMware ESXi, la version 5.0 n'est pas encore suffisamment stable à mon goà»t (les derniers patchs posent problème) Cependant, je pense qu'il est aisé de suivre le tutoriel sous la version 5.0 de DSM qui est assez similaire, exceptée la refonte de l'interface graphique. Pré-requis pour ce tutoriel : Une box/routeur Internet Un NAS Synology Un nom de domaine DNS Une adresse IP fixe, ou à défaut un système de DynDNS Liens permettant d'approfondir le sujet : http://forum.hardware.fr/hfr/reseauxpersosoho/Reseaux/synology-dsm-disponible-sujet_5497_686.htm#t741030 http://www.nas-forum.com/forum/topic/39737-tuto-haproxy-et-regroupement-des-parametrages-trouves-sur-le-fofo/
  25. Compatible uniquement 4.x (pour la 3.60 ... c'est ICI ... merci DMK2424) L'idée est de générer automatiquement le tableau d'ID utilisé dans GEA ou autres scripts. Ainsi, il sera possibile à chaque mise à jour de votre HC2, de simplement relancer le générateur, copier le résultat dans GEA et vos ID seront donc remis à jour. Voici le tableau dont je parle : local id = { --inconnu LUA_SNIPPETS = 141, --Garage OREGON = 128, SURPRESSEUR = 118, CAMERA = 123, PORTE_GARAGE = 238, DETECTEUR_PORTE = 112, PORTE_GARAGE_GARAGE = 64, --Jardin TEMPERATURE = 69, SEISMOMETRE = 71, HUMIDITE = 261, DETECTEUR = 68, NETATMO = 137, PLUVIOMETRE = 262, LUMINOSITE = 70, LAMPE_OUEST = 234, PLUIE = 139, COIN_REPAS = 14, PRESSION_ATMOSPHERIQ = 258, TERRASSE = 160, METEOALERTE = 150, ARROSAGE = 158, NETATMO_EXTERIEUR = 260, --Local Technique LIVEBOX = 251, IPX800_RELAIS = 106, PORTE_LOCAL = 56, VMC_DOUBLE_FLUX = 114, LAVE_LINGE = 120, PLAFONNIER = 54, PASSERELLE_NETATMO = 135, PASSERELLE_ZIBASE = 126, --Entrée CAMERA_ENTREE = 129, DETECTEUR_ENTREE = 5, LUMINOSITE_ENTREE = 7, SEISMOMETRE_ENTREE = 8, PLAFONNIER_ENTREE = 10, PORTE_ENTREE = 58, TEMPERATURE_ENTREE = 6, --Cuisine SIRENE = 200, BRITA__FILTRE_ = 131, CUISINE = 237, CAPTEUR_FUMEE = 46, ALARME_FUMEE = 48, FRIGO = 52, TEMPERATURE_CUISINE = 47, LAVE_VAISSELLE = 50, TABLETTE = 176, --Chambre parentale SECHE_SERVIETTE = 60, --Salon CHAUFFAGE = 104, HUMIDITE_SALON = 257, CO2 = 256, NETATMO_SALON = 255, SONOMETRE = 259, POELE = 34, OREGON_SALON = 127, TV = 39, HIFI = 42, BLUE_RAY = 41, OPENKAROTZ = 133, ROMBA = 43, LUMIERE_SALON = 107, PRISE_LIBRE = 44, BRISE_SOLEIL = 105, WI = 40, KAROTZ = 134, NETATMO_SALON_SALON = 136, --Chambres PLAFONNIER_KENDRA = 23, PLAFONNIER_NORA = 18, TEMPERATURE_CHAMBRES = 147, FENETRE_NORA = 143, FENETRE_KENDRA = 145, OREGON_CHAMBRES = 138, FENETRE_NOLAN = 149, PLAFONNIER_NOLAN = 21, --Couloir PORTE_TERRASSE = 153, APLIQUE_ESCALIER = 25, TEMPERATURE_AU_SOL = 155, SPOTS = 230, LEDS_ESCALIER = 27, --Divers ANDROID_FILES = 162, IMPERIHOME = 208, TYPE_DE_JOURNEE = 110, EVENEMENTS = 173, NETATMO_DIVERS = 253, CLOCK_SYNC = 252, UPDATE_NOTIFIER_1_0_6 = 206, AGENDA = 178, MY_BATTERIES = 130, VACANCES_SCOLAIRES = 151, } Ce générateur ce base sur les noms des modules et des pièces que vous avez déclarer. Il va donc parcourir tous vos modules, prendre leur nom et le transformer (majuscule, suppression caractères spéciaux, ...). Si le nom existe deux fois, il va le suffixer du nom de la pièces (ex : DETECTEUR_GARAGE). Donc, si comme moi, vous ne changer pas régulièrement le nom de vos modules, ce générateur va vous permettre de gagner quelques précieuses minutes. Usage ... simple, copier le code ci-dessous et lancer le script avec le bouton "start". Une fois le script terminé, il va vous affiché le tableau dans la fenêtre de debug, il ne vous suffira plus que de le copier dans vos scripts. Il est possible de spécifier les ID ou type de module que vous ne voulez pas prendre en compte. Vous pouvez aussi préciser si vous souhaiter prendre en compte les modules caché ou mort. Voici donc le script dans sa globalité : --[[ %% properties %% globals --]] local hidden = false --- true pour exporter les devices cachés local dead = false -- true pour exporter les devices morts local excludeType = {"com.fibaro.zwaveDevice", "weather", "HC_user", "iOS_device", "com.fibaro.voipUser"} local excludeID = {} local devicesJSon = api.get("/devices") local devices = {} local names = {} local rooms = {} function addName(name, roomname) if (type(names[name]) == "nil") then names[name] = true return name else return addName(name.."_"..roomname, roomname) end end function getRooms() local roomsJSon = api.get("/rooms") rooms[0] = "inconnu" for k, v in ipairs(roomsJSon) do rooms[v.id] = v.name end end function rename(name, roomname) local name = name:upper():gsub("[éêèà«]", "E"):gsub("EE", "E"):gsub("[à»à¼ù]", "U"):gsub("UU", "U"):gsub("[à âà¤]", "A"):gsub("AA", "A"):gsub("[à¶ô]", "O"):gsub("OO", "O"):gsub("[îà¯]", "I"):gsub("II", "I"):gsub("%W", "_") local roomname = roomname:upper():gsub("[éêèà«]", "E"):gsub("EE", "E"):gsub("[à»à¼ù]", "U"):gsub("UU", "U"):gsub("[à âà¤]", "A"):gsub("AA", "A"):gsub("[à¶ô]", "O"):gsub("OO", "O"):gsub("[îà¯]", "I"):gsub("II", "I"):gsub("%W", "_") return addName(name, roomname) end getRooms() for k, v in pairs(devicesJSon) do local doit = (hidden or v.visible) and (dead or not v.dead) if (doit) then for h, w in pairs(excludeType) do if (v.type == w) then doit = false end end if (doit) then for h, w in pairs(excludeID) do if (v.id == w) then doit = false end end end end if (doit) then table.insert(devices, v) end end table.sort(devices, function(a, return a.roomID<b.roomID end) local result = "<BR><BR>-- IDs générés le : " .. os.date("%d/%m/%y à %X") local room = -1 local lastinfo = ""; result = result .. "<BR><BR>local id = {" for k, v in ipairs(devices) do if (room ~= v.roomID) then room = v.roomID result = result .. "<BR>--"..rooms[v.roomID].."<BR>" end lastinfo = rename(v.name, rooms[v.roomID]) result = result .. lastinfo .. " = " .. v.id .. ", " end result = result .. "<BR>}" result = result .. "<BR>" result = result .. "<BR>-- usage :" result = result .. "<BR>-- fibaro:getValue(id[\""..lastinfo .."\"], \"value\")" result = result .. "<BR>-- GEA.add(id[\""..lastinfo .."\"], 30, \"\")" print(result) Il ne vous restera plus qu'à utiliser les ID ainsi fibaro:getValue(id["DETECTEUR_GARAGE"], "value") GEA.add(id["DETECTEUR_GARAGE"], -1, "La porte du garage est entrain de s'ouvrir") ATTENTION : Les déclencheurs doivent et devront toujours être changé par vos soins ATTENTION 2 : Si vous ne comprenez pas l'usage de ce script, c'est sà»rement parce que vous n'en avez pas l'utilité Icone by @Did (Merci)
×