Aller au contenu

Rechercher dans la communauté

Affichage des résultats pour les étiquettes 'tutoriel'.



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é
    • 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

Calendriers

Aucun résultat à afficher.


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

19 résultats trouvés

  1. Sauvegarde Home Center 3 sur NAS Synology Version 3.22 - Janvier 2024 Voici un script Shell à installer sur un NAS Synology, permettant d'automatiser la sauvegarde de la box Home Center 3. La sauvegarde est externalisée et stockée sur le NAS. Un rapport par email est envoyé, ainsi qu'une notification dans l'interface Web de DSM. Installation Télécharger le fichier backup-hc3.sh ci-joint, et le copier sur le NAS. Modifier le script afin de paramétrer les options suivantes : HC3 Address HC3_ADDRESS : Adresse IP de la HC3. Par exemple "192.168.1.1" HC3 Authentication : echo -n 'user:password' | base64 ou https://www.base64encode.org/ HC3_AUTHENTICATION : Identifiants de connexions encodés en base64. Utiliser le site https://www.base64encode.org/ par exemple pour admin:password cela donne "YWRtaW46cGFzc3dvcmQ=". L'utilisateur doit avoir les droits "Administrateur" sur la box. HC3 Backup History HC3_BACKUP_HISTORY : doit prendre la valeur "YES" afin de sauvegarder l'historique. Si la sauvegarde est trop longue ou trop grosse, il est possible de désactiver la sauvegarde de l'historique en attribuant n'importe quelle autre valeur à cette variable, par exemple "NO". HC3 Global Variable HC3_VARIABLE_NAME : nom d'une variable à tester pour bloquer le déclenchement de la sauvegarde, par exemple "Vacances" HC3_VARIABLE_IS_VALUE : valeur que doit avoir la variable éventuellement définie pour déclencher la sauvegarde, par exemple "0" HC3 Active Profile (on peut filtrer sur aucun profil, 1 seul, ou les 2, dans ce dernier cas c'est un ET logique qui est effectué, c'est à dire que les 2 conditions doivent être vraies) : HC3_PROFIL_IS_VALUE : ID du profil actif permettant de déclencher la sauvegarde. Si le profil actif est égal à cette valeur, alors la sauvegarde est démarrée. HC3_PROFIL_NOT_VALUE : ID du profil qui ne doit pas être actif pour déclencher la sauvegarde. Si le profil actif est égal à cette valeur, alors la sauvegarde est bloquée. NAS NAS_PATH : chemin complet sur le NAS dans lequel copier le fichier sauvegarder, normalement il s'agit du même répertoire qui contient le script, par exemple "/volume1/backup/HC3" Email MAIL_FROM : adresse email source, par exemple : "HC3 <moi@domaine.com>" MAIL_TO : adresse email cible, par exemple "Moi <moi@domaine.com>" MAIL_SUBJECT : titre de l'email, par exemple "Backup HC3" Notification NOTIF_TO : destinataire des notifications sur le NAS, par exemple "@administrators" NOTIF_TITLE : titre de la notification, par exemple "Sauvegarde" Backup timeout TIMEOUT : durée maximale en secondes de la sauvegarde autorisée avant que le script ne considère que la box est plantée, par exemple pour 10 minutes : 600 Reboot CLEAN_REBOOT : focer un reboot complet de la box après chaque sauvegarde, valeur par défaut "No" FORCE_REBOOT : forcer le reboto de la box si les services n'ont pas correctement redémarrés après la sauvegarde, valeur par défaut "Yes" Sur l'interface Web de DSM, ouvrir le Panneau de configuration, sélectionner le Planificateur de tâches, puis Créer / Tâche planifiée / Script défini par l'utilisateur : Dans l'onglet "Général", taper un nom de tâche et utiliser le compte "admin" : Dans l'onglet "Programmer", sélectionner un jour et une heure, par exemple chaque dimanche à 3h du matin : Dans l'onglet "Paramèters de la tâche", entrer l'adresse email destinataire des rapports, et la commande suivante pour exécuter le script (remplacer éventuellement le chemin s'il est différent chez vous) : set -o pipefail; "/volume1/backup/HC3/backup-hc3.sh" 2>&1 | tee -a "/volume1/backup/HC3/backup-hc3.out" Utilisation Attendre... Lorsque la planification se déclenche, un email est envoyé : Une notification apparait dans l'interface Web de DSM : Un nouveau fichier fbi contenant la sauvegarde (chiffrée) est présent sur le NAS, ainsi qu'un fichier journal backup-hc3.out : Exécution immédiate : Si on est impatient et qu'on veut tester immédiatement le script, le plus efficace est d'ouvrir une session SSH en ligne de commande (utiliser PuTTY sous Windows) et de l'exécuter directement : admin@DiskStation:~$ /volume1/backup/HC3/backup-hc3.sh Backup Fibaro Home Center : Saturday 11/07/2020 19:10:03 Vérification de la valeur de la variable globale 'Vacances'... Variable globale 'Vacances' = '0' identique à '0' => Sauvegarde Vérification du profil actif... Profil actif = '1' => Sauvegarde Sauvegarde avec historique... ........................................................................... Sauvegarde terminée Téléchargement de backup_HC3-00000000_2020_07_11-19_10_28.fbi... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 794k 100 794k 0 0 8028k 0 --:--:-- --:--:-- --:--:-- 8108k Téléchargement terminé Pas de reboot du Home Center Backup terminé avec succès : Saturday 11/07/2020 19:12:02 (penser à activer préalablement le serveur SSH dans le panneau de configuration de DSM si ce n'est pas déjà fait) Téléchargement : backup-hc3.sh Bonus : script pour HC2 & HCL : backup-hc2.sh Pour HC2 à partir du firmware 4.621 : voir script de @speedoxx007 en page 4.
  2. 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/
  3. Utilisation de net.HTTPClient() asynchrone - dans une scène en LUA sur HC2/HC3 - - dans un QuickApp sur HC3 - Dans les scènes, Fibaro ne nous laisse pas le choix, dès que l'on veut faire des appels HTTP, on est obligé d'utiliser la fonction asynchronse net.HTTPClient(). La fonction Net.FHTTP() synchrone utilisée dans les VD n'est pas disponible dans les scènes. Toutefois, l'avantage de net.HTTPClient() est d'accepter les connexions sécurisées HTTPS devenues majoritaires sur Internet. Exemple de code simple pour une requête de type GET local http = net.HTTPClient() http:request("http://1.2.3.4/url", { success = function(response) if response.status == 200 then print('OK, réponse : '.. response.data) else print("Erreur : status=" .. tostring(response.status)) end end, error = function(err) print("Erreur : " .. err) end, options = { method = 'GET' } }) L'exemple suivant effectue une requête de type POST permettant d'envoyer des données vers le site distant. De plus, la fonction success() récupère les données de type JSON en vue d'un traitement ultérieur (notez que les données envoyées vers le site Web et les données reçues depuis le site Web sont différentes, cela dépend de l'application qui tourne sur le site) : -- Les données à envoyer au formulaire local myJson = { "couleurs": { [1] = "bleu", [2] = "blanc", [3] = "rouge" }, "fruits": { [1] = "pomme", [2] = "banane" }, } -- Appel HTTPS local http = net.HTTPClient() http:request("https://www.domaine.com/url", { success = function(response) if response.status == 200 then if response.data and response.data ~= "" then print('Retour : '.. response.data) local jsonTable = json.decode(response.data) -- Parcours de la table JSON local k, v for k, v in pairs(jsonTable) do print("key = " .. k .. " - type(v) = " .. type(v)) end -- Ici la suite du code, exécuté en asynchrone, donc après la fin de l'exécution du code appelant http:request() -- ... else print("Error : empty response data") end else print("Erreur : status=" .. tostring(response.status)) end end, error = function(err) print("Erreur : " .. err) end, options = { method = 'POST', timeout = 5000, checkCertificate = false, headers = { ["content-type"] = 'application/x-www-form-urlencoded;', ["Authorization"] = "Basic YWRtaW46cGFzc3dvcmQ=" -- username:password encodé en Base64 (admin:password) }, data = json.encode(myJson) } }) -- Ici la suite du code, exécuté en synchrone, donc avant l'exécution du contenu de la fonction success() -- ... On remarque dans les options que l'on peut choisir les paramètres suivants : method : obligatoire : GET ou PUT ou POST ou DELETE timeout : facultatif : délai d'attente en millisecondes avant échec de la requête. Peut être utile avec certains serveurs un peu trop lents à répondre. Dans le doute, inutile d'utiliser ce paramètre. checkCertificate : facultatif : true ou false, permet d'ignorer les alertes de sécurité sur les certificats auto-signés (non reconnus pas une autorité de certification approuvée) headers : facultatif : permet de passer le(s) en-tête(s) HTTP de son choix vers le site Web distant. Si vous ne savez pas ce qu'est un Header, c'est que vous n'avez probablement pas besoin d'envoyer de header, donc ignorez ce paramètre. data : facultatif : ce sont les données à envoyer dans les formulaires POST et PUT sous forme de chaine de caractères. Donc si les données sont de type tableau JSON, il faut les encoder avec json.encode(). Asynchronisme net.HTTPClient() est asynchrone, le code dans les fonctions success() et error() appelées en callback s'exécute toujours après la fin de l'exécution du thread principal. Quand on commence à programmer en asynchrone, il ne faut plus jamais utiliser de fonctions synchrones comme sleep(), sous peine de comportement surprenant. Préférer à la place l'emploi de la fonction settimout() qui est elle-même asynchrone (chercher les exemples sur le forum) La bonne pratique quand on programme en asynchrone est la suivante : Après un appel à net.HTTPClient(), le code devrait se terminer le plus rapidement possible afin de laisser la main à la fonction success() appelée en callback de net.HTTPClient(). La suite du code se déroule donc dans la fonction success(). Celle-ci, à sont tour, peut faire d'autres appels à net.HTTPClient() ou settimeout() pour déclencher de nouveaux appels de fonctions en callback asynchrone. Etc... C'est la technique que j'ai employé dans mes scènes Watchdog et Yamaha MusicCast, partagées sur le forum. C'est une certaine gymnastique qui n'est pas évidente au début, et oblige à revoir toute la structure de son code LUA. En complément je vous invite à lire ce sujet sur la protection des requêtes http avec pcall() :
  4. J3R3M

    [VD+Scène] Netatmo Welcome

    Bonjour à tous, Jusqu'à peu, j'utilisais uniquement des requêtes fing (ping) pour détecter les différents téléphones de mon téléphone et ainsi en déduire la présence de quelqu'un ou non à mon domicile. Seulement, ce n'était pas assez fiable et j'ai décidé de combiner cette solution à la Netatmo Welcome. Après quelques recherches, je suis tombé sur ce topic du site Siio (également et heureusement disponible en anglais ici). C'est exactement ce que je recherchais! Seulement, je l'ai modifié pour qu'il soit plus simple à à mettre en place et à utiliser au quotidien. Ainsi, il n'y a rien à faire à part modifier les variables vous concernant. Pour utiliser le script original, il faut créer deux Variables Globales par personne identifiée dans la base de données de la Welcome, ce que je ne trouve pas très ergonomique et lourd. Je précise qu'une très grande partie du script provient du lien précédent et je ne cherche pas à tirer la gloire de l'auteur original (BOOMX) de celui-ci malgré mes modifications. Je l'ai modifiée comme je le souhaitais et ai traduit les debugs. J'espère que cette scène vous sera utile et suis disponible pour répondre à vos éventuelles questions! Exemple d'utilisation Pour savoir si quelqu'un est présent d'après la Netatmo Welcome, il suffit d'utiliser un code comme-ci dans vos scènes et VD : local pseudo = "Jérémy"; local VGNetatmo = "NETATMO_Welcome"; local table = json.decode(fibaro:getGlobalValue(VGNetatmo)); local presence = tonumber(table[pseudo].status); if presence == 1 then fibaro:debug(pseudo.." est présent."); else fibaro:debug(pseudo.." est absent."); end Réglages de la Scène Netatmo Welcome Toutes les variables permettant de régler la scène sont au début de celle-ci. Après avoir saisi les bonnes informations, enregistrez et démarrez la scène manuellement. La scène est fonctionnelle ! NB : Ces paramètres étant envoyés via une requête HTTP, merci d'encoder les caractères spéciaux. Pour rappel : @ = %40 -- Informations de compte Netatmo local client_id = 'Client_id'; local client_secret = 'Client_secret'; local username = 'Netatmo_username'; local password = 'Netatmo_pass'; -- Informations du VD associé local vd_ID = 304; -- ID du VD associé local vd_refresh = 9; -- ID du bouton refresh du VD. 9 Par défaut -- Réglages de la scène local refresh = 10; -- Script executé toutes les x secondes. Pas moins de 8s! local debug = 0; -- Faut-il vraiment l'expliquer ? -- Nom de la Variable Globale qui sera créée et utilisée par la scène et le VD local VGNetatmo = "NETATMO_Welcome"; Trouver ses Client ID & Client Secret Pour obtenir vos client_id et client_secret, rendez-vous sur dev.netatmo.com et connectez-vous. Cliquez sur CREATE YOUR APP et remplissez rapidement le formulaire. Les informations saisies importent peu! Une fois que vous aurez validé en cliquant sur le bouton SAVE, d'autres fenêtres apparaîtront en-dessous. Celle qui nous intéresse et celle juste en-dessous. En effet, les informations Client id et Client secret sont dans la section Technical Parameters. Faites un copier/coller de ces informations dans les variables correspondantes et le tour est joué! J'ai tellement ramé à les trouver que je me devais de vous dire où ces informations étaient dissimulées! Limitations de l'API Netatmo En ce qui concerne la variable refresh, il s'agit du délai entre chaque mise à jour des informations par la scène. L'auteur explique très bien pourquoi il ne faut pas descendre en dessous des 8 secondes et je vais me contenter de traduire son explication. VD Netatmo Welcome Pour personnaliser celui-ci, rendez-vous au début du code du bouton refresh : -- Les pseudos doivent être exactement les mêmes que dans l'application Netatmo, séparés par une virgule local pseudos = {"Jérémy","Emilie","Maman"}; -- Nombre de personnes à afficher dans le VD -- Si modification, conserver la même structure de VD ! -- Et penser à modifier la variable "vd_refresh" de la scène Netatmo local NbPersonnes = 3; -- Variable Globale local VGNetatmo = "NETATMO_Welcome"; Si vous souhaitez conserver seulement les informations de 3 personnes, il vous suffit de modifier uniquement les valeurs de la variable pseudos. Attention, les pseudos doivent être rigoureusement les mêmes que ceux enregistrés dans Netatmo! Si vous souhaitez afficher plus de 3 personnes, conservez obligatoirement la même structure du VD, c'est-à-dire en ajoutant 3 étiquettes dont les IDs seront incrémentés de +1 pour chaque nouvelle personne. Pour information, le VD d'origine est beaucoup moins optimisé puisque vous devez modifier tout le code du bouton pour qu'il soit fonctionnel. Scène Netatmo Welcome Une seule instance autorisée. Démarrage Automatique --[[ %% autostart --]] -- Informations de compte Netatmo local client_id = 'Client_id'; local client_secret = 'Client_secret'; local username = 'Netatmo_username'; local password = 'Netatmo_pass'; -- Informations du VD associé local vd_ID = 304; -- ID du VD associé local vd_refresh = 9; -- ID du bouton refresh du VD. 9 Par défaut -- Réglages de la scène local refresh = 10; -- Script executé toutes les x secondes. Pas moins de 8s! local debug = 0; -- Faut-il vraiment l'expliquer ? -- Nom de la Variable Globale qui sera créée et utilisée par la scène et le VD local VGNetatmo = "NETATMO_Welcome"; -------------------------------------------------------------- -------- Ne rien modifier à partir de cette ligne ------------ -------------------------------------------------------------- local token = ''; local request_body = ''; Debug = function (color, message) if (debug == 1) then fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")); elseif (debug == 0) then end end DebugChange = function (color, message) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")); end DebugError = function (color, message) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")); end fibaro:debug('Démarrage du script Netatmo welcome Integration v.1.0'); if (debug == 0) then fibaro:debug("Debug = 0. Seuls les messages d'information apparaîtront dans les logs."); else fibaro:debug('Debug = 1. Messages de Debug activés.'); end fibaro:debug('Cette scène sera executée toutes les ' ..refresh.. ' secondes.'); -- Début - Ajout pour gestion indépendante des VG function CreerVG(VGNom, VGValeur) local data = {name = VGNom, value=VGValeur}; response, status = api.post("/globalVariables", data); if (status == 201) then DebugError("white", "Variable Globale " .. VGNom .. " créée."); else DebugError("red", "Impossible de créer la Variable Globale " .. VGNom .. "!"); end end function MajEntree(Nom, Statut, Lastseen) local table = json.decode(fibaro:getGlobalValue(VGNetatmo)); -- Tout est à mettre à jour if Nom ~= nil and Statut ~= nil and Lastseen ~= nil then table[Nom] = {status=Statut, lastseen=Lastseen}; fibaro:setGlobal(VGNetatmo,json.encode(table)); DebugError("yellow", "L'entrée " .. Nom .. " a été automatiquement créée."); -- Mise à jour du Statut elseif Nom ~= nil and Statut ~= nil and Lastseen == nil then table[Nom].status = Statut; fibaro:setGlobal(VGNetatmo,json.encode(table)); Debug("yellow", "Le statut de " .. Nom .. " a été mis sur la valeur ".. Statut); -- Mise à jour de la dernière vue de la personne elseif Nom ~= nil and Statut == nil and Lastseen ~= nil then table[Nom].lastseen = Lastseen; fibaro:setGlobal(VGNetatmo,json.encode(table)); Debug("yellow", "L'information 'lastseen' de " .. Nom .. " a été mise sur la valeur ".. Lastseen); else DebugError("red", "Erreur lors de l'utilisation de la fonction MajEntree"); if Nom == nil then DebugError("white", "Champ 'Nom' vide !"); end if Statut == nil then DebugError("white", "Champ 'Statut' vide !"); end if Lastseen == nil then DebugError("white", "Champ 'Lastseen' vide !"); end end end if fibaro:getGlobalValue(VGNetatmo) == nil then CreerVG(VGNetatmo,json.encode({})); end -- Fin - Ajout pour gestion indépendante des VG function oAuth(nextFunction) local request_body = 'grant_type=password&client_id=' .. client_id .. '&client_secret=' .. client_secret .. '&username=' .. username .. '&password=' .. password .. '&scope=read_camera'; getResponseData('https://api.netatmo.net/oauth2/token', request_body, function(data) if (data.access_token ~= nil) then token = data.access_token gethomedata() else DebugError( "red", "Impossible de joindre l'API!"); end end ) setTimeout(oAuth, refresh*1000); end function getResponseData(url, body, func) local http = net.HTTPClient(); http:request(url, { options = { method = 'POST', headers = {['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'}, data = body, checkCertificate = false }, success = function(response); func(json.decode(response.data)); end }) end function gethomedata() request_body_cam = 'access_token=' ..token.. ''; getResponseData('https://api.netatmo.net/api/gethomedata', request_body_cam, function(getData) if (getData.body ~= nil) then for w, v in pairs(getData.body.homes) do for a, b in pairs(v.persons) do local INFOS = json.decode(fibaro:getGlobalValue(VGNetatmo)); if (b.pseudo ~= nil) then if (b.out_of_sight == false) then if INFOS[b.pseudo] ~= nil then MajEntree(b.pseudo,nil,b.last_seen); local change_var = tonumber(INFOS[b.pseudo].status); if (change_var == 0) then DebugChange("green", b.pseudo.. ' est présent.') MajEntree(b.pseudo,1,nil); else Debug("white", b.pseudo.. ' est toujours présent.'); end else Debug("red", "L'entrée pour " ..b.pseudo.. " de la table "..VGNetatmo.." n'éxiste pas."); MajEntree(b.pseudo,0,0); end else if INFOS[b.pseudo] ~= nil then MajEntree(b.pseudo,nil,b.last_seen); local change_var2 = tonumber(INFOS[b.pseudo].status); if (change_var2 == 1) then DebugChange( "orange", b.pseudo.. ' est absent.'); MajEntree(b.pseudo,0,nil); else Debug( "white", b.pseudo.. ' est toujours absent.'); end else Debug("red", "L'entrée pour " ..b.pseudo.. " de la table "..VGNetatmo.." n'éxiste pas."); MajEntree(b.pseudo,0,0); end end end end end else Debug("red", "Impossible de joindre l'API! Vérifier le taux de rafraichissemment!"); end if tonumber(vd_ID) ~= nil then fibaro:call(vd_ID, "pressButton", vd_refresh); end end ) end local sourceTrigger = fibaro:getSourceTrigger(); if (sourceTrigger["type"] == "autostart") then oAuth(); end Icones Téléchargement du VD Netatmo_Welcome.vfib
  5. Détecter les erreurs et protéger l'exécution d'un script LUA avec pcall() Il existe déjà un vieux sujet de @Shad, mais je vais essayer d'être un peu plus exhaustif, en prenant en compte les nouveautés apportées par les scènes sur HC2 puis les QuickApp sur HC3 : l"utilisation de la librairie net.HTTPClient() et l'exécution asynchrone du code LUA. Autre sujet détaillant l'utilisation de net.HTTPClient() à lire au préalable : Durant l'exécution d'un script LUA, une erreur peut survenir, susceptible de planter le script, celui-ci s'arrête alors brutalement et la suite du code n'est jamais exécutée. Je paraphrase l'explication de @Krikroff : Pour faire simple: La fonction pcall() permet l’exécution du code en mode "protégé" ou "encapsulé", c'est à dire qu'il ne lèvera pas d' erreur dans le processus de votre box si jamais le code provoquait une erreur. Ainsi, le fil d'exécution des Scènes et des QuickApps est protégé. Aussi à savoir: pcall() retourne true ou false en fonction de la réussite du code mais peut aussi retourner un résultat issu de la fonction en utilisant la méthode interne error(). La fonction pcall() peut-être utilisée pour faire en LUA l'équivalent du try...catch pour ceux qui connaissent. Des exemples ici pour comprendre : Programming in LUA : 8.4 - Error Handling and Exceptions Programming in LUA : 8.5 – Error Messages and Tracebacks Exemple n°1 : protection de http:request() Le premier usage de pcall() est pour protéger l'exécution de la fonction http:request() car celle-ci peut planter, par exemple si l'URL est mal formée : local http = net.HTTPClient() local url = "http://192.168.1.1/chemin/page?argument=valeur" local status, err = pcall(function() http:request(url, { success = function(response) -- Suite des traitements... end, error = function(err) -- Gestion de l'erreur (connexion impossible) end, options = { -- options éventuelles... } }) -- http:request() end) -- pcall() if not status then -- Gestion de l'erreur attrapée par pcall() print(err) end Exemple n°2 : protection de json.decode() De plus, pcall() est également très utile (voire indispensable) pour une autre fonction qui a la fâcheuse habitude de planter : json.decode() si le JSON donné en argument est mal formaté. Exemple : local status, jsonTable = pcall(function() return json.decode(response.data) end) if status then -- Suite des traitements... else print(jsonTable or "json.decode() failed") end Dans cet exemple, la variable jsonTable contiendra soit le tableau décodé (résultat de json.decode()), soit le message d'erreur (résultat de pcall()) Exemple n°3 : protection complète de http:request() et json.decode() Par ailleurs, il faut noter que dans le premier exemple avec http:request(), les fonctions success() et error() sont des fonctions de callback appelées après l'exécution de la requête, donc elles sont asychrones. De ce fait, leur contenu n'est plus protégé par la fonction pcall(). Par conséquent, si on combine les 2 exemples précédents, à savoir la requête HTTP, puis le décodage du résultat JSON, cela donne une structure de code comme suit : local http = net.HTTPClient() local status, err = pcall(function() http:request(url, { success = function(response) local status, jsonTable = pcall(function() return json.decode(response.data) end) if status then -- Suite des traitements... else print(jsonTable or "json.decode() failed") end end, error = function(err) -- Gestion de l'erreur (connexion impossible) end, options = { -- options éventuelles... } }) -- http:request() end) -- pcall() if not status then -- Gestion de l'erreur attrapée par pcall() print(err) end De cette façon, le code LUA est parfaitement protégé. Exemple n°4 : interruption conditionnelle de l'exécution avec assert() La fonction assert() permet de tester une condition. Si la résultat est false, dans ce cas elle déclenche l'erreur qui sera attrapée par pcall() : local http = net.HTTPClient() local status, err = pcall(function() -- Ici mon code s'exécute et effectue plein d'actions... local device = api.get("/devices/127") assert(type(device) == "table", "Le module 127 est introuvable") -- Suite du code si tout se passe bien... end) -- pcall() if not status then -- Gestion de l'erreur attrapée par pcall() print(err) end Dans cet exemple j'ai testé si le résultat d'un appel à api.get() s'est bien passé, mais on pourrait tester n'importe quel autre cas de figure. Exemple n°5 : interruption inconditionnelle de l'exécution avec error() La fonction error() permet de forcer le déclenchement d'une erreur qui sera attrapée par pcall() : local http = net.HTTPClient() local status, err = pcall(function() -- Ici mon code s'exécute et effectue plein d'actions... if ma_condition then error("Un message d'erreur") end -- Suite du code si tout se passe bien... end) -- pcall() if not status then -- Gestion de l'erreur attrapée par pcall() print(err) end J'espère que ce petit tutoriel sera utile, vous pouvez maintenant utiliser pcall() dans vos code, combiner les différents exemples ci-dessus, etc.
  6. Bonjour, Il existe déjà plusieurs Virtual Devices relatifs à l'Eco-Devices sur le forum mais n'ayant pas trouvé mon bonheur, j'ai entièrement écrit un module de zéro en fonction de mes besoins et en espérant qu'il puisse également servir à d'autres. Que fait ce Virtual Device ? 1) Suivi en temps réel des statistiques d'un compteur téléinfo (T1 ou T2) HC/HP 2) Affichage temps réel d'une icône de type "jauge" présentant le tarif actuel (HC/HP) ainsi que la valeur de consommation actuelle 3) Affichage temps des index en kWatts au 1000ième, index en cours (HC ou HP) toujours en premier 4) Affichage temps réel d'un compteur de consommation journalier en Watts pour les HP et les HC 5) Affichage temps réel du coà»t de consommation journalier 6) Génération d'un rapport Email de consommation journalière 7) Fonction de remise à zéro manuelle des compteurs journaliers 8) Gestion de l'authentification utilisateur Eco-Devices Evolutions prévues : 1) Ajout d'un compteur de cumul mensuel 2) Estimation de prochaine facture et publication d'index "Releve Confiance" chez EDF (fera certainement l'objet d'un second module "EDF & Moi") Voici un aperçu des vues graphiques du Virtual Device : La liste des icones de jauges : Deux méthodes sont proposées pour la récupération des statistiques de l'Eco-Devices : L'existence de ces 2 méthodes est liée à un bug connu de la HC2 lors de l'utilisation de requêtes HTTP dans la mainLoop d'un Virtual Device qui bloque au bout d'un certain temps. Le moyen de contourner cela est l'utilisation d'un bouton déclenché depuis la mainLoop qui a comme inconvénient de modifier l'icône pour la durée du traitement ce qui personnellement ne me convient pas. - Méthode 1 (recommandée) : C'est la méthode que j'ai choisi car elle se base sur une scène afin de rafraichir les données et évite ainsi le changement d'icône indésirable durant la récupération des données. -> Pour utiliser cette méthode, vous devez en plus créer et configurer la scène fournie puis dans la MainLoop, positionner la variable useSceneToRefresh à true - Méthode 2 (par défaut ) : C'est la méthode configurée par défaut qui évite l'utilisation d'une scène en parallèle mais avec l'inconvénient de l'icône qui sera modifiée à chaque récupération des données. J'ai toutefois crée une icône dédiée à configurer sur ce bouton : afin que ce ne soit pas trop moche. -> Pour utiliser cette méthode, vous devez simplement positionner la variable useSceneToRefresh à false dans la MainLoop Comment l'utiliser ? 1) Importer la dernière version du Virtual Device : Eco_Devices_Live_Day_Reporter_V0.1.vfib 2) Renseignez l'adresse IP ainsi que le port (80 par défaut) de votre Eco-Devices 3) Importer la série d'icônes de jauges fournies en respectant l'ogre dans lequel elles sont fournies, c'est très important, puis notez l'Id correspondant à la première 4) Dans la mainLoop, renseignez les valeurs des variables teleInfoNB, baseIconId, userIdsToNotify, useSceneToRefresh et si besoin reportTime 5) Si vous utilisez la Méthode 1 (useSceneToRefresh = true) vous devez créer la scène Eco-Devices Refresh (voir ci-dessous) 6) Dans le code du bouton "Raraîchir" pensez à saisir vos in formations d'authentification si vous l'avez activée sur l'Eco-Devices 7) Pas besoin de créer de variables globales, elles sont automatiquement crées au premier démarrage du Virtual Device 8) Sauvegarder la scène et tout devrait bien fonctionner Pour ceux qui utilisent la Méthode 1 : Voici le code de la scènes Eco-Devices Refresh Il est IMPORTANT de bien renseigner le deviceId correspondant à l'Id de votre Virtual device importé ci-dessus. Si vous avez activé l'authentification sur l'Eco-Devices, vous devez ici saisir vos informations d'authentification encodées en base64. Si vous ne l'avez pas déjà fait, il suffit d'aller sur https://www.base64encode.org, d'encoder en UTF8 la chaine correspondante à "<login>:<password>" et de récupérer le résultat. Par exemple "admin:password" donnera "YWRtaW46cGFzc3dvcmQ=" saut de --[[ %% autostart %% properties %% globals --]] -- Récurrence de rafraichissement des stats en secondes local checkEvery = 3 -- Id du Virtual Device local deviceId = 228 -- Authentification ("" si pas d'authentification sinon chaine "<login>:<password>" en base64 local base64BasicAuthentication = "" local sourceTrigger = fibaro:getSourceTrigger() local ecoDevicesIP = tostring(fibaro:get(deviceId,"IPAddress")) local ecoDevicesStats = nil --- Usefull Functions --- function debug(text, color) color = color or "white" fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, text, "span")) end function setDevicePropertyValue(id, label, value) fibaro:call(id, "setProperty", "ui."..label..".value", value) end function getDevicePropertyValue(vDeviceid, propertyName) return fibaro:getValue(vDeviceid, "ui."..propertyName..".value") end function refreshEcoDevicesStats() debug("Rafraichissement des statistiques de l'EcoDevices...") ecoDevicesStats = nil local http = net.HTTPClient() http:request("http://"..ecoDevicesIP.."/api/xdevices.json?cmd=10", { options = { method = 'GET', headers = {["Authorization"] = 'BASIC '..base64BasicAuthentication}, }, success = function(response) ecoDevicesStats = response.data refreshEcoDevicesStatsAsync() end, error = function(err) debug("Error: " ..err, "red") fibaro:sleep(1000) refreshEcoDevicesStats() end }) end function refreshEcoDevicesStatsAsync() fibaro:setGlobal("ecoDevicesStats", ecoDevicesStats) debug("OK ! "..ecoDevicesStats, "green") if (sourceTrigger["type"] == "autostart") then setTimeout(refreshEcoDevicesStats, checkEvery*1000) end end refreshEcoDevicesStats() lignesaut de ligne Enfin, voici le code de la MainLoop : saut de ligne -------------------------------------------------------- -- Eco-Devices Live & Day Reporter v0.1 -- -------------------------------------------------------- -- Auteur : Brice Cassagnabère -- -------------------------------------------------------- -- Changelog : -- -- -- -- v0.1 : Version initiale -- -------------------------------------------------------- -- Plus d'infos : http://is.gd/tMgWdy -- -------------------------------------------------------- -- Renseignez ici le numéro de téléinfo à prendre en compte, T1 ou T2 teleInfoNB = "T1" -- Renseignez ici le numéro de la première icône de jauge (HC_0.png) baseIconId = 1047 -- Renseignez ici les id Utilistaurs à qui transmettre le rapport userIdsToNotify = {2, 154} -- Si vous utilisez la scène associée pour la MAJ, passer cette variable à true useSceneToRefresh = false -- Heure à laquelle vous souhaitez générer le rapport journalier reportTime = "23:59" -- Tarifs des kWh 2015 hcCost = 0.0623 hpCost = 0.1019 deviceId = fibaro:getSelfId() --- Usefull Functions --- function debug(text, color) color = color or "white" fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, text, "span")) end function setDevicePropertyValue(id, label, value) fibaro:call(id, "setProperty", "ui."..label..".value", value) end function getDevicePropertyValue(vDeviceid, propertyName) return fibaro:getValue(vDeviceid, "ui."..propertyName..".value") end function createGlobalIfNotExists(varName, defaultValue) if fibaro:getGlobal(varName) == "" then debug("Création de la variable "..varName.." avec comme valeur par défaut "..defaultValue) newVar = {} newVar.name = varName newVar.value = defaultValue HC2 = Net.FHttp("127.0.0.1", 11111) HC2:POST("/api/globalVariables", json.encode(newVar)) end end function refreshEcoDevicesStats() if not useSceneToRefresh then fibaro:call(deviceId, "pressButton", 5) fibaro:sleep(1000) end jsonStats = fibaro:getGlobalValue("ecoDevicesStats") if not string.find(jsonStats, '{"product":"Eco-') then debug("An error occured -> "..jsonStats, "red") debug("No stats found, please check documentation and configuration", "orange") return false end ecoDevicesStats = json.decode(jsonStats) tarif = string.format("%.2s", ecoDevicesStats[teleInfoNB.."_PTEC"]) conso = ecoDevicesStats[teleInfoNB.."_PAPP"] hcIndex = ecoDevicesStats[teleInfoNB.."_HCHC"] hpIndex = ecoDevicesStats[teleInfoNB.."_HCHP"] hcIndexStr = "HC : "..string.format("%.3f", hcIndex/1000) hpIndexStr = "HP : "..string.format("%.3f", hpIndex/1000) fibaro:log("Tarif : "..tarif.." - Conso : "..conso.." VA".." - "..hcIndexStr.." - "..hpIndexStr) iconId = baseIconId if tarif == "HP" then activeIndex = hpIndexStr inactiveIndex = hcIndexStr iconId = iconId + 9 else activeIndex = hcIndexStr inactiveIndex = hpIndexStr end -- Mise à jour des Labels setDevicePropertyValue(deviceId, "labelTarif", tarif) setDevicePropertyValue(deviceId, "labelConso", conso.." VA") setDevicePropertyValue(deviceId, "labelActiveIndex", activeIndex.." kW") setDevicePropertyValue(deviceId, "labelInactiveIndex", inactiveIndex.." kW") -- Mise à jour de l'icône conso = ecoDevicesStats[teleInfoNB.."_PAPP"] if conso >= 1000 then if conso < 9000 then iconId = iconId + tonumber(string.format("%.1s", conso)) else iconId = iconId + 8 end end fibaro:call(deviceId, "setProperty", "currentIcon", iconId) return true end function refreshDayStats() day_HC_Conso = hcIndex - day_HC_Index day_HP_Conso = hpIndex - day_HP_Index day_HC_ConsoStr = "HC : "..day_HC_Conso.." W" day_HP_ConsoStr = "HP : "..day_HP_Conso.." W" if tarif == "HP" then activeDayIndex = day_HP_ConsoStr inactiveDayIndex = day_HC_ConsoStr else activeDayIndex = day_HC_ConsoStr inactiveDayIndex = day_HP_ConsoStr end -- Calcul du coà»t en € dayCost = ((day_HP_Conso * hpCost) + (day_HC_Conso * hcCost)) / 1000 dayCost = dayCost + (dayCost * 0.2) dayCostStr = "Coà»t : "..string.format("%.2f", dayCost).." €" setDevicePropertyValue(deviceId, "labelActiveDayIndex", activeDayIndex) setDevicePropertyValue(deviceId, "labelInactiveDayIndex", inactiveDayIndex) setDevicePropertyValue(deviceId, "labelToday", dayCostStr) end function reportDayStats() message = "HC : "..day_HC_Conso.." Watts\nHP : "..day_HP_Conso.." Watts\n"..dayCostStr for k,v in pairs(userIdsToNotify) do fibaro:call(v, "sendEmail", "Consommation électrique du "..os.date("%d/%m/%Y"), message) end end function checkCptRaz() -- Tous les jours à minuit, je stockera valeur de l'index en cours if tostring(os.date("%H:%M")) == reportTime or day_HC_Index == 0 or ecoDevicesStats.raz then debug("Initialisation du compteur journalier", "green") if tostring(os.date("%H:%M")) == reportTime then reportDayStats() end day_HC_Index = hcIndex day_HP_Index = hpIndex fibaro:setGlobal("day_HC_Index", day_HC_Index) fibaro:setGlobal("day_HP_Index", day_HP_Index) while tostring(os.date("%H:%M")) == reportTime do fibaro:sleep(1000) end end end -- Création automatique des variable globales createGlobalIfNotExists("ecoDevicesStats", "0") createGlobalIfNotExists("day_HC_Index", "0") createGlobalIfNotExists("day_HP_Index", "0") -- Je rafraichis les stats une première fois pour initialiser mes variables locales if not refreshEcoDevicesStats() then return end day_HC_Index = tonumber(fibaro:getGlobalValue("day_HC_Index")) day_HP_Index = tonumber(fibaro:getGlobalValue("day_HP_Index")) -- Boucle principale while true do -- ## Pensez à bien choisir votre méthode de mise à jour des stats -- ## Méthode 1 (useSceneToRefresh = true) ## : Vous utilisez la Scene de Mise à jour des stats qui évite -- le changement d'icône indésirable -- ## Méthode 2 (useSceneToRefresh = false) ## : Pas besoin de créer la scene mais entrainera un court changement -- de l'icône durant le reresh contrairement à la précédente if not refreshEcoDevicesStats() then return end refreshDayStats() checkCptRaz() fibaro:sleep(2000) end saut de ligne Historique des versions : - V0.1 du 11/05/2015 : Eco_Devices_Live_Day_Reporter_V0.1.vfib
  7. IPX800 V4 : Pilotage des relais Contexte : Après avoir galléré pour trouver un Tuto sur le Forum expliquant comment piloter un IPX800 V4, je partage avec vous un exemple d'usage de l'IPX. Mon exemple est de pouvoir modifier l'état d'un des relais de l'IPX qui active le relais d'une sirène d'alarme. Je suis parti de l'exemple de @Moicphil Utiliser Une Sirène Extérieure Filaire Avec La Hc2 / Hclite , mais dans son cas il utiliser un IPX800 V3 alors moi j'utilise un IPX800 V4 et pour lequel les commandes ne sont pas les mêmes. Voici un extrait de la documentation de l'API de l'IPX800V4 : L'ensemble de l'API est protégée par une clef secrète. Par défaut, cette clef est : « apikey ». Elle est bien sur paramétrable et il est également possible de supprimer cette protection. Lors de l'utilisation de l'API JSON, il sera nécessaire de renseigner cette clef à chaque commande. Pour cela, dans tous les cas, il vous suffira de la placer en premier argument de la manière suivante : « key=apikey ». Les requêtes JSON commenceront donc de la manière suivante : « http://IPX800_V4/api/xdevices.json?key=apikey&... ». Elles pourront également comprendre plusieurs commandes à la fois (même si cela aura un impact sur la réponse). Exemple 1 : commande qui met le relais 01 de l'IPX800V4 à 1 (fonction SetR=) http://192.168.0.10/api/xdevices.json?key=apikey&SetR=01 Exemple 2 : commande qui met le relais 01 de l'IPX800V4 à 0 (fonction ClearR=) http://192.168.0.10/api/xdevices.json?key=apikey&ClearR=01 Exécution de ces commandes sous son explorateur, avec le résultat suivant : { "product": "IPX800_V4", "status": "Success" } Transposition de ces commandes en LUA dans un VD qui déclenche/arrête la Sirène : Bouton On (déclenche la sirène) : local _deviceIp = fibaro:get(fibaro:getSelfId(), 'IPAddress') -- get the adress off ipx800V4 HC2 = Net.FHttp(_deviceIp) response = HC2:GET("/api/xdevices.json?key=apikey&ClearR=01") Bouton Off (arrête la sirène) : local _deviceIp = fibaro:get(fibaro:getSelfId(), 'IPAddress') -- get the adress off ipx800V4 HC2 = Net.FHttp(_deviceIp) response = HC2:GET("/api/xdevices.json?key=apikey&SetR=01") Documentations de l'IPX800 V4 : mode-d'emploiIPX800V4.pdf IPX_API.pdf
  8. Bonjour, Voilà un moment que je cherchais le moyen de piloter les projecteurs de mes caméras « Présence » (j'en ai une côté cour et une autre côté jardin). C'est chose faite et je partage ma solution si cela peut aider quelqu'un. Tout d'abord merci à @KiboOst, qui « sévit » sur le forum jeedom, pour son excellent « php-simpleNetatmoAPI ». D'après ce que j'ai compris il s'agit d'un travail de reverse engineering qui s'est terminé par un retour aux API Netatmo ... sauf, qu'en fouillant dans les API officielles de Netatmo, je n'ai trouvé nulle part le moyen de piloter l'allumage du projecteur et encore moins de gérer sa luminosité ! Donc ma solution : - Côté Serveur (mon Raspberry) installation des composants de « php-simpleNetatmoAPI » sur mon Raspberry création d'un fichier TXT de paramétrage de l'API et des projecteurs écriture d'un script PHP destiné à exécuter une action sur un projecteur - Côté Home Center création d'un VD pour piloter mes 2 projecteurs simultanément ... outil prêt pour une utilisation future, ex : allumer tous les extérieurs de la maison en cas de fête et/ou d'intrusion Un peu de contenu si cela vous intéresse : Côté HC2, le VD et ses icônes Côté Raspberry, le fichier TXT et le script PHP Et voilou ... enjoy Cordialement - Jean-Paul Le VD L'export du VD est disponible en fichier joint. Sur le Raspberry 1 - Fichier texte de paramètrages User=.......... Password=.......... ClientId=.......... ClientSecret=.......... Projo1Home=3 Projo1Name=Présence avant Projo2Home=1 Projo2Name=Présence arrière 2 - Script PHP <?php //-------------------------------------------------------------------------------------------------- // // Script de commande du projecteur d'une caméra Presence Netatmo // // Inspiration : https://github.com/KiboOst/php-simpleNetatmoAPI // // Principe : // 1 - Les infos de connexion sont enregistrées dans un fichier texte sur ce serveur // . les 4 premières lignes sont dédiées à la connexion à l'API Netatmo // . puis une paire de lignes par caméra (ligne 1 = code 'Maison', ligne 2 = nom 'Présence') // 2 - Pour connaître les 'Home' et 'Name' des projecteurs : // . ne saisir que les 4 premières lignes dans le fichier texte // . lancer le script comme ceci : /ProjoAutoOnOff.php?projo=1&action=on // . lire ce qui s'affiche // . rechercher "Si le nombre de projecteurs est égal à zéro" dans le code // . débloquer/dupliquer les lignes en commentaires en remplacant 'xx' par le/les codes 'Maison' // 3 - En entrée : // . le numéro du projecteur à piloter (1 ou 2 ... ou plus) // . la commande à envoyer au projecteur ('auto', 'on' et 'off') // 4 - En sortie : // . commande OK // . commande non effectuée car le projo est déjà à l'état demandé // . autre (erreur) // //-------------------------------------------------------------------------------------------------- $Verbose = false; /* Validation du code action */ $Action = $_GET["action"]; if (strlen($Action) == 0) { exit('Missing action code'); } else { if ($Action != 'auto' and $Action != 'on' and $Action != 'off') { exit('Invalid action code'); } } if ($Verbose) {echo 'Code action ----> ', $Action, '<br>';} /* Récupération du numéro de projecteur */ $NumProjo = $_GET["projo"]; if (strlen($NumProjo) == 0) { exit('Missing floodlight number'); } if ($Verbose) {echo 'Numéro de projecteur ----> ', $NumProjo, '<br>';} /* Ouverture du fichier des infos de connexion au routeur et retourne un tableau contenant une ligne par élément */ $lines = file('ProjosCredentials.txt'); $NbLines = count($lines); if ($Verbose) { foreach ($lines as $lineNumber => $lineContent) { echo $lineNumber,' ',$lineContent, '<br>'; } echo 'Nombre de lignes : ', $NbLines, '<br>'; } /* Vérification du nombre de lignes */ if (($NbLines % 2) == 1) { exit('Invalid line number (odd)'); } /* Chargement des variables de connexion */ $Netatmo_User = ""; $Netatmo_Psw = ""; $Netatmo_ClientID = ""; $Netatmo_ClientSecret = ""; /* ----> Netatmo User */ $mystring = trim($lines[0]); $findme = 'User='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Netatmo User'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Netatmo User'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $Netatmo_User = substr($mystring, strlen($findme)); } } /* ----> Netatmo Password */ $mystring = trim($lines[1]); $findme = 'Password='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Netatmo Password'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Netatmo Password'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $Netatmo_Psw = substr($mystring, strlen($findme)); } } /* ----> Netatmo Client ID */ $mystring = trim($lines[2]); $findme = 'ClientId='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Netatmo Client ID'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Netatmo Client ID'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $Netatmo_ClientID = substr($mystring, strlen($findme)); } } /* ----> Netatmo Client Secret */ $mystring = trim($lines[3]); $findme = 'ClientSecret='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Netatmo Client Secret'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Netatmo Client Secret'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $Netatmo_ClientSecret = substr($mystring, strlen($findme)); } } /* Chargement des numéros de projecteurs */ $i = 4; $NbProjo = 0; $TabProjo = array(); while ($i < $NbLines) { $NbProjo = $NbProjo + 1; $mystring = trim($lines[$i]); $findme = 'Projo' . $NbProjo . 'Home='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Floodlight' . $NbProjo . ' Home'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Floodlight' . $NbProjo . ' Home'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $TabProjo[$NbProjo][1] = substr($mystring, strlen($findme)); } } $i = $i + 1; $mystring = trim($lines[$i]); $findme = 'Projo' . $NbProjo . 'Name='; $pos = strpos($mystring, $findme); if ($pos === false) { echo "La chaîne '$findme' ne se trouve pas dans la chaîne '$mystring'", '<br>'; exit('Error retrieving Floodlight' . $NbProjo . ' Name'); } else { if ($pos <> 0) { echo 'La chaîne ', $findme, ' n\'est pas au début de ', $mystring, '<br>'; exit('Error retrieving Floodlight' . $NbProjo . ' Name'); } else { if ($Verbose) {echo "La chaine '$findme' a été trouvée dans la chaîne '$mystring' et débute à la position $pos", '<br>';} $TabProjo[$NbProjo][2] = substr($mystring, strlen($findme)); } } $i = $i + 1; } if ($Verbose) { echo 'Netatmo User = ', $Netatmo_User, '<br>'; echo 'Netatmo Password = ', $Netatmo_Psw, '<br>'; echo 'Client ID = ', $Netatmo_ClientID, '<br>'; echo 'Client Secret = ', $Netatmo_ClientSecret, '<br>'; echo 'Nombre de projecteurs = ', $NbProjo, '<br>'; echo 'Table des projecteurs :', '<br>'; for ($i=1; $i<=$NbProjo; $i++) { echo 'Presence', $i, ' Home = ', $TabProjo[$i][1], ' - Presence', $i, ' Name = ', $TabProjo[$i][2], '<br/>'; }; } // Si le nombre de projecteurs est égal à zéro on récupère les infos "Homes" if ($NbProjo == 0) { require($_SERVER['DOCUMENT_ROOT']."/php-simpleNetatmoAPI/class/splNetatmoAPI.php"); $_splNetatmo = new splNetatmoAPI($Netatmo_User, $Netatmo_Psw, $Netatmo_ClientID, $Netatmo_ClientSecret); if (isset($_splNetatmo->error)) die($_splNetatmo->error); // Liste des maisons avec le nombre de caméras rattachées $homes = $_splNetatmo->getHomes(); echo "<pre><br>homes:<br>".json_encode($homes, JSON_PRETTY_PRINT)."</pre><br>"; // -------------------------------------------------------------------------------------------------------------------------------- // Remplacer 'xx' dans l'instruction suivante par le code maison obtenu et décommenter les lignes pour obtenir les infos 'Présence' // // $_splNetatmo = new splNetatmoAPI($Netatmo_User, $Netatmo_Psw, $Netatmo_ClientID, $Netatmo_ClientSecret, xx); // $Cameras = $_splNetatmo->getPresenceCameras(); // echo "<pre>Cameras:<br>".json_encode($Cameras, JSON_PRETTY_PRINT)."</pre><br>"; // --------------------------------------------------------------------------------------------------------------------------------- exit ('Please enter the projectors codes (House and Name)'); } /* Validation du numéro de projecteur */ if ($NumProjo < 1 or $NumProjo > $NbProjo) { exit('Invalid floodlight number'); } // C'est parti /* Récupération du statut du projecteur */ require($_SERVER['DOCUMENT_ROOT']."/php-simpleNetatmoAPI/class/splNetatmoAPI.php"); $ProjoHome = $TabProjo[$NumProjo][1]; $ProjoName = $TabProjo[$NumProjo][2]; $_splNetatmo = new splNetatmoAPI($Netatmo_User, $Netatmo_Psw, $Netatmo_ClientID, $Netatmo_ClientSecret, $ProjoHome); $Cameras = $_splNetatmo->getPresenceCameras(); $StatusProjo = $Cameras[$ProjoName]['light_mode_status']; if ($Verbose) { echo "<pre>Cameras :<br>".json_encode($Cameras, JSON_PRETTY_PRINT)."</pre><br>"; echo "Status du projo '", $ProjoName, "' de la maison '", $ProjoHome, "' = ", $StatusProjo, '<br>'; } /* Si le projo est déjà à l'état demandé on ne fait rien */ if ($Action == $StatusProjo) { if ($Verbose) {echo 'Changement du status du projecteur inutile - On arrête', '<br>';} exit('Floodlight already set'); } /* On passe le projo à l'état demandé */ $_splNetatmo->setLightMode($ProjoName, $Action); if ($Verbose) {echo "Projecteur passé à '", $Action, "'", '<br>';} exit('Floodlight set'); ?> Projecteurs_Caméras.vfib.json
  9. Scène pour afficher l'utilisation des variables globales Références croisées (xref) Lorsque les développements prennent une certaine ampleur, et en absence d'atelier de développement logiciel, il est utile de de pouvoir rapidement identifier quel morceau de code utilise telle variable (globale dans le cas de la HC2). Ce sujet avait déjà été abordé il y a maintenant quelque temps : Je vous en propose une nouvelle version qui permet : D'obtenir pour chaque variable globale les scènes et VD qui en font usage ; Pour chaque scène et pour chaque VD d'avoir la liste des variables globales utilisées (c'est cela qui est nouveau). Voici un exemple des résultats affichés dans le fenêtre de debug : La scène est un peu longue lors de son exécution, je suis preneur d'idées d'algorithmes plus optimisés. Le code de la scène : --[[ This scene is used to list all the global variables and where they are used. It's a kind of xref. -- 07/02/2017: creation -- 24/10/2019: add scene and virtual devices --]] local startTime = os.time(); local globalVariables = api.get("/globalVariables"); -- Get all globals variables local scenes = api.get("/scenes?type=com.fibaro.luaScene&isLua=true"); -- all the scenes local devices = api.get("/devices?type=virtual_device"); -- and all the virtual devices since for others types there is no lua code function round(num, numDecimalPlaces) return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num)); end -- round function progressBar(progressPct, length) if length ~= nil or length == 0 then length = 20; end progressPct = math.abs(progressPct); progressPct = math.min(progressPct, length); return ' [' .. string.rep("*", progressPct) .. string.rep("_", length - progressPct) .. '] '; end -- progressBar fibaro:debug('<font color="Gold">Analyzing lua code for ' .. #globalVariables .. ' global variables, ' .. #scenes .. ' scenes, ' .. #devices .. ' virtual devices, this may take a while.</font>'); -- Where each global variable is used local txt = '<BR><font color="yellow">'.. string.rep('=', 80) .. '<BR>Globals variables ' .. os.date("%d/%m/%y %X") .. '</font><BR>'; local cnt = 0; for _, glob in pairs(globalVariables) do -- For each global variable txt = txt .. '<BR><font color="Orange">Global variable "' .. glob.name .. '":</font>'; cnt = cnt + 1; local used = false; for _, s in pairs(scenes) do -- For each scene local scene = api.get("/scenes/" .. s.id); if scene.triggers.globals ~= nil then for _, g in pairs(scene.triggers.globals) do -- We look each trigger if (g ~= nil) and (g == glob.name) then txt = txt .. '<BR><font color="lightgreen">&nbsp&nbsp&nbsp- trigger in scene "' .. scene.name .. '" (id:' .. scene.id .. ')</font>'; used = true; end end end -- Lua code inspection if (scene.lua ~= nil) and (string.find(scene.lua, glob.name) ~= nil) then txt = txt .. '<BR><font color="Chartreuse">&nbsp&nbsp&nbsp- used in scene "' .. scene.name .. '" (id:' .. scene.id .. ')</font>'; used = true; end end -- for _, s in pairs(scenes) for _,device in pairs(devices) do -- For each virtual device if (device.properties.mainLoop ~= nil) and (string.find(device.properties.mainLoop, glob.name) ~= nil) then -- look in mainloop txt = txt .. '<BR><font color="DeepSkyBlue">&nbsp&nbsp&nbsp- used in VD "' .. device.name .. '" mainloop</font>'; used = true; end local rows = device.properties.rows; -- look in buttons for _, row in pairs(rows) do if (row.type ~= nil) and (row.type == "button") and (row.elements ~= nil) then for _,element in pairs(row.elements) do if (element.lua ~= nil) and (element.lua == true) then if (element.msg ~= nil) and (string.find(element.msg, glob.name) ~= nil) then txt = txt .. '<BR><font color="LightSkyBlue">&nbsp&nbsp&nbsp- used in "' .. element.name .. '" btn (id: ' .. element.id .. ') of "' .. device.name .. '" VD (' .. device.id .. ')</font>'; used = true; end end end end end end -- for _,d in pairs(devices) if not used then txt = txt .. "<font color='Magenta'> unused</font>"; end local progress = round((cnt / #globalVariables) * 100) if (progress % 5) == 0 then fibaro:debug('<font color="gray">working,' .. progressBar(progress/5, 20) .. tostring(progress) .. '% done in ' .. (os.time()-startTime) .. ' secondes.</font>'); end end txt = txt .. '<BR><font color="gray">Total memory in use by Lua (version '.._VERSION..'): ' .. string.format("%.2f", collectgarbage("count")) .. ' KB</font>'; txt = txt .. '<BR><font color="gray">Time for global variables: ' .. (os.time()-startTime) .. ' secondes.</font><BR>'; -- Global variables used by scenes local sceneTime = os.time(); txt = txt .. '<BR><font color="yellow">'.. string.rep('=', 80) .. '<BR>Global variables used by scene ' .. os.date("%d/%m/%y %X") .. '</font><BR>'; for _, s in pairs(scenes) do -- For each scene txt = txt .. '<BR><font color="lightgreen">Scene "' .. s.name .. '" (id:'.. s.id .. '):</font>'; local used = false; local scene = api.get("/scenes/" .. s.id); if scene.triggers.globals ~= nil then for _, g in pairs(scene.triggers.globals) do -- We look each trigger for _, glob in pairs(globalVariables) do -- For each global variable if (g == glob.name) then txt = txt .. '<BR><font color="Orange">&nbsp&nbsp&nbsp- global "' .. glob.name .. ' used as a trigger"</font>'; used = true; end end -- for _, glob end end -- Lua code inspection if (scene.lua ~= nil) then for _, glob in pairs(globalVariables) do -- For each global variable if (string.find(scene.lua, glob.name) ~= nil) then txt = txt .. '<BR><font color="Coral">&nbsp&nbsp&nbsp- global "' .. glob.name .. '" used</font>'; used = true; end end -- for _, glob end if not used then txt = txt .. "<font color='Magenta'> no global variable used</font>"; end end -- for _, s in pairs(scenes) txt = txt .. '<BR><font color="gray">Total memory in use by Lua (version '.._VERSION..'): ' .. string.format("%.2f", collectgarbage("count")) .. ' KB</font>'; txt = txt .. '<BR><font color="gray">Time for scenes: ' .. (os.time()-sceneTime) .. ' secondes.</font><BR>'; -- Global variables used by virtual devices local deviceTime = os.time(); txt = txt .. '<BR><font color="yellow">'.. string.rep('=', 80) .. '<BR>Global variables used by virtual devices ' .. os.date("%d/%m/%y %X") .. '</font><BR>'; for _,device in pairs(devices) do -- For each virtual device txt = txt .. '<BR><font color="DeepSkyBlue">Virtual device "' .. device.name .. '" (id:'.. device.id .. '):</font>'; local used = false; if (device.properties.mainLoop ~= nil) then -- look in mainloop for _, glob in pairs(globalVariables) do -- For each global variable if (string.find(device.properties.mainLoop, glob.name) ~= nil) then txt = txt .. '<BR><font color="Orange">&nbsp&nbsp&nbsp- global "' .. glob.name .. '" used in mainloop</font>'; used = true; end end end local rows = device.properties.rows; -- look in buttons for _, row in pairs(rows) do if (row.type ~= nil) and (row.type == "button") and (row.elements ~= nil) then for _,element in pairs(row.elements) do for _, glob in pairs(globalVariables) do -- For each global variable if (element.lua ~= nil) and (element.lua == true) then if (element.msg ~= nil) and (string.find(element.msg, glob.name) ~= nil) then txt = txt .. '<BR><font color="Coral">&nbsp&nbsp&nbsp- global "' .. glob.name .. '" used in btn "' .. element.name .. '" (id:' .. element.id .. ')</font>'; used = true; end end end end end end if not used then txt = txt .. "<font color='Magenta'> no global variable used</font>"; end end -- for _,device txt = txt .. '<BR><font color="gray">Total memory in use by Lua (version '.._VERSION..'): ' .. string.format("%.2f", collectgarbage("count")) .. ' KB</font>'; txt = txt .. '<BR><font color="gray">Time for virtual devices: ' .. (os.time()-deviceTime) .. ' secondes.</font>'; txt = txt .. '<BR><font color="gray">Total elapsed time: ' .. (os.time()-startTime) .. ' secondes.</font><BR>'; fibaro:debug(txt); Je vous propose l'icône que j'utilise et suis preneur d'une qui serait plus "artistique". A l'approche des frimas, je ne puis que conclure par un... Chaleureusement.
  10. macpowered

    Caméra Freebox Delta dans la HC2

    Bonjour, J'avais posté récemment sur le forum une question concernant la caméra livrée avec le pack sécurité de la Freebox Delta. Quant à savoir comment l'intégrer dans la HC2. En cherchant bien, j'ai fini par réussir à l'intégrer ! Tout d'abord, il vous faut récupérer l'IP locale de la caméra dans la console d'administration de la freebox (DHCP -> Baux actif, la mienne s'appelle un truc du genre r0F65). Pensez à lui attribuer cet IP en statique. Ensuite, ajouter une redirection de port pour cette IP sur le port 80 (ou 443 si vous préférez passer par https) en mettant le port qui vous convient (exemple 8989,9090,etc) On va partir du postulat que l'adresse IP de ma caméra est 192.168.0.20 et que je redirige le port 8989 sur le port 80 de cette IP. Un fois cela fait, reste à trouver le login et le mot de passe de cette caméra. Rien de plus simple. Dans votre navigateur, taper cette URL : http://mafreebox.freebox.fr/api/v6/home/tileset/all et recherchez (ctrl+F) le terme freeboxcam (c'est le login par défaut de la caméra) Vous devriez tomber sur un truc du genre : "http://freeboxcam:+YR5dPwn@192.168.0.20/img/stream.m3u8" On voit donc que le login est freeboxcam et le mot de passe est +YR5dPwn Vous voilà paré pour ajouter votre jolie caméra dans la HC2. Dans Modules -> Ajouter un dispositif faite Ajouter dans la section Ajouter une caméra Rendez-vous dans la section paramètres avancés. Nom : ce que vous voulez Pièce : où vous voulez Modèle de la caméra : Autre modèle Utilisateur : freeboxcam Mot de passe : +YR5dPwn (celui-là c'est celui de mon exemple) Protocol : Http ou Https selon que vous ayez redirigé le port 80 ou 443 sur l'IP de la caméra Adresse IP : 192.168.0.20:8989 (celle-là c'est toujours celle de mon exemple, à vous d'adapter) URL JPG : /img/snapshot.cgi?size=4 (le size=4 correspond à une image toutes les 4 secondes, à modifier selon vos besoins) URL du flux MPEG : /img/stream.m3u8 et voilà, le tour est joué !! Vous avez une joli caméra de plus dans la HC2. J'espère que mon astuce servira à certains. Pour ma part, ça m'a permis de trouver une vraie utilité à cette caméra qui croupissait dans son carton.
  11. Bonsoir, Si comme moi vous souhaitez piloter votre TV Sony mais que le Plugin Sony développé par Fibaro ne fonctionne pas, , voici une scéne et un VD qui permettont de piloter la TV via notre HC2. Pour commencer : _ Créer une variable globale en la nommant : cmd_sony_tv _ Créer une scène en LUA et copier ce code : --[[ %% autostart %% properties %% globals --]] local ip = 'xxx.xxx.x.xx' local port = '80' local xAuthPSK = '1111' local irCode = json.decode([[ [ {"name":"Num1","value":"AAAAAQAAAAEAAAAAAw=="}, {"name":"Num2","value":"AAAAAQAAAAEAAAABAw=="}, {"name":"Num3","value":"AAAAAQAAAAEAAAACAw=="}, {"name":"Num4","value":"AAAAAQAAAAEAAAADAw=="}, {"name":"Num5","value":"AAAAAQAAAAEAAAAEAw=="}, {"name":"Num6","value":"AAAAAQAAAAEAAAAFAw=="}, {"name":"Num7","value":"AAAAAQAAAAEAAAAGAw=="}, {"name":"Num8","value":"AAAAAQAAAAEAAAAHAw=="}, {"name":"Num9","value":"AAAAAQAAAAEAAAAIAw=="}, {"name":"Num0","value":"AAAAAQAAAAEAAAAJAw=="}, {"name":"Num11","value":"AAAAAQAAAAEAAAAKAw=="}, {"name":"Num12","value":"AAAAAQAAAAEAAAALAw=="}, {"name":"Enter","value":"AAAAAQAAAAEAAAALAw=="}, {"name":"GGuide","value":"AAAAAQAAAAEAAAAOAw=="}, {"name":"ChannelUp","value":"AAAAAQAAAAEAAAAQAw=="}, {"name":"ChannelDown","value":"AAAAAQAAAAEAAAARAw=="}, {"name":"VolumeUp","value":"AAAAAQAAAAEAAAASAw=="}, {"name":"VolumeDown","value":"AAAAAQAAAAEAAAATAw=="}, {"name":"Mute","value":"AAAAAQAAAAEAAAAUAw=="}, {"name":"TvPower","value":"AAAAAQAAAAEAAAAVAw=="}, {"name":"Audio","value":"AAAAAQAAAAEAAAAXAw=="}, {"name":"MediaAudioTrack","value":"AAAAAQAAAAEAAAAXAw=="}, {"name":"Tv","value":"AAAAAQAAAAEAAAAkAw=="}, {"name":"Input","value":"AAAAAQAAAAEAAAAlAw=="}, {"name":"TvInput","value":"AAAAAQAAAAEAAAAlAw=="}, {"name":"TvAntennaCable","value":"AAAAAQAAAAEAAAAqAw=="}, {"name":"WakeUp","value":"AAAAAQAAAAEAAAAuAw=="}, {"name":"PowerOff","value":"AAAAAQAAAAEAAAAvAw=="}, {"name":"Sleep","value":"AAAAAQAAAAEAAAAvAw=="}, {"name":"Right","value":"AAAAAQAAAAEAAAAzAw=="}, {"name":"Left","value":"AAAAAQAAAAEAAAA0Aw=="}, {"name":"SleepTimer","value":"AAAAAQAAAAEAAAA2Aw=="}, {"name":"Analog2","value":"AAAAAQAAAAEAAAA4Aw=="}, {"name":"TvAnalog","value":"AAAAAQAAAAEAAAA4Aw=="}, {"name":"Display","value":"AAAAAQAAAAEAAAA6Aw=="}, {"name":"Jump","value":"AAAAAQAAAAEAAAA7Aw=="}, {"name":"PicOff","value":"AAAAAQAAAAEAAAA+Aw=="}, {"name":"PictureOff","value":"AAAAAQAAAAEAAAA+Aw=="}, {"name":"Teletext","value":"AAAAAQAAAAEAAAA\/Aw=="}, {"name":"Video1","value":"AAAAAQAAAAEAAABAAw=="}, {"name":"Video2","value":"AAAAAQAAAAEAAABBAw=="}, {"name":"AnalogRgb1","value":"AAAAAQAAAAEAAABDAw=="}, {"name":"Home","value":"AAAAAQAAAAEAAABgAw=="}, {"name":"Exit","value":"AAAAAQAAAAEAAABjAw=="}, {"name":"PictureMode","value":"AAAAAQAAAAEAAABkAw=="}, {"name":"Confirm","value":"AAAAAQAAAAEAAABlAw=="}, {"name":"Up","value":"AAAAAQAAAAEAAAB0Aw=="}, {"name":"Down","value":"AAAAAQAAAAEAAAB1Aw=="}, {"name":"ClosedCaption","value":"AAAAAgAAAKQAAAAQAw=="}, {"name":"Component1","value":"AAAAAgAAAKQAAAA2Aw=="}, {"name":"Component2","value":"AAAAAgAAAKQAAAA3Aw=="}, {"name":"Wide","value":"AAAAAgAAAKQAAAA9Aw=="}, {"name":"EPG","value":"AAAAAgAAAKQAAABbAw=="}, {"name":"PAP","value":"AAAAAgAAAKQAAAB3Aw=="}, {"name":"TenKey","value":"AAAAAgAAAJcAAAAMAw=="}, {"name":"BSCS","value":"AAAAAgAAAJcAAAAQAw=="}, {"name":"Ddata","value":"AAAAAgAAAJcAAAAVAw=="}, {"name":"Stop","value":"AAAAAgAAAJcAAAAYAw=="}, {"name":"Pause","value":"AAAAAgAAAJcAAAAZAw=="}, {"name":"Play","value":"AAAAAgAAAJcAAAAaAw=="}, {"name":"Rewind","value":"AAAAAgAAAJcAAAAbAw=="}, {"name":"Forward","value":"AAAAAgAAAJcAAAAcAw=="}, {"name":"DOT","value":"AAAAAgAAAJcAAAAdAw=="}, {"name":"Rec","value":"AAAAAgAAAJcAAAAgAw=="}, {"name":"Return","value":"AAAAAgAAAJcAAAAjAw=="}, {"name":"Blue","value":"AAAAAgAAAJcAAAAkAw=="}, {"name":"Red","value":"AAAAAgAAAJcAAAAlAw=="}, {"name":"Green","value":"AAAAAgAAAJcAAAAmAw=="}, {"name":"Yellow","value":"AAAAAgAAAJcAAAAnAw=="}, {"name":"SubTitle","value":"AAAAAgAAAJcAAAAoAw=="}, {"name":"CS","value":"AAAAAgAAAJcAAAArAw=="}, {"name":"BS","value":"AAAAAgAAAJcAAAAsAw=="}, {"name":"Digital","value":"AAAAAgAAAJcAAAAyAw=="}, {"name":"Options","value":"AAAAAgAAAJcAAAA2Aw=="}, {"name":"Media","value":"AAAAAgAAAJcAAAA4Aw=="}, {"name":"Prev","value":"AAAAAgAAAJcAAAA8Aw=="}, {"name":"Next","value":"AAAAAgAAAJcAAAA9Aw=="}, {"name":"DpadCenter","value":"AAAAAgAAAJcAAABKAw=="}, {"name":"CursorUp","value":"AAAAAgAAAJcAAABPAw=="}, {"name":"CursorDown","value":"AAAAAgAAAJcAAABQAw=="}, {"name":"CursorLeft","value":"AAAAAgAAAJcAAABNAw=="}, {"name":"CursorRight","value":"AAAAAgAAAJcAAABOAw=="}, {"name":"ShopRemoteControlForcedDynamic","value":"AAAAAgAAAJcAAABqAw=="}, {"name":"FlashPlus","value":"AAAAAgAAAJcAAAB4Aw=="}, {"name":"FlashMinus","value":"AAAAAgAAAJcAAAB5Aw=="}, {"name":"AudioQualityMode","value":"AAAAAgAAAJcAAAB7Aw=="}, {"name":"DemoMode","value":"AAAAAgAAAJcAAAB8Aw=="}, {"name":"Analog","value":"AAAAAgAAAHcAAAANAw=="}, {"name":"Mode3D","value":"AAAAAgAAAHcAAABNAw=="}, {"name":"DigitalToggle","value":"AAAAAgAAAHcAAABSAw=="}, {"name":"DemoSurround","value":"AAAAAgAAAHcAAAB7Aw=="}, {"name":"*AD","value":"AAAAAgAAABoAAAA7Aw=="}, {"name":"AudioMixUp","value":"AAAAAgAAABoAAAA8Aw=="}, {"name":"AudioMixDown","value":"AAAAAgAAABoAAAA9Aw=="}, {"name":"PhotoFrame","value":"AAAAAgAAABoAAABVAw=="}, {"name":"Tv_Radio","value":"AAAAAgAAABoAAABXAw=="}, {"name":"SyncMenu","value":"AAAAAgAAABoAAABYAw=="}, {"name":"Hdmi1","value":"AAAAAgAAABoAAABaAw=="}, {"name":"Hdmi2","value":"AAAAAgAAABoAAABbAw=="}, {"name":"Hdmi3","value":"AAAAAgAAABoAAABcAw=="}, {"name":"Hdmi4","value":"AAAAAgAAABoAAABdAw=="}, {"name":"TopMenu","value":"AAAAAgAAABoAAABgAw=="}, {"name":"PopUpMenu","value":"AAAAAgAAABoAAABhAw=="}, {"name":"OneTouchTimeRec","value":"AAAAAgAAABoAAABkAw=="}, {"name":"OneTouchView","value":"AAAAAgAAABoAAABlAw=="}, {"name":"DUX","value":"AAAAAgAAABoAAABzAw=="}, {"name":"FootballMode","value":"AAAAAgAAABoAAAB2Aw=="}, {"name":"iManual","value":"AAAAAgAAABoAAAB7Aw=="}, {"name":"Netflix","value":"AAAAAgAAABoAAAB8Aw=="}, {"name":"Assists","value":"AAAAAgAAAMQAAAA7Aw=="}, {"name":"ActionMenu","value":"AAAAAgAAAMQAAABLAw=="}, {"name":"Help","value":"AAAAAgAAAMQAAABNAw=="}, {"name":"TvSatellite","value":"AAAAAgAAAMQAAABOAw=="}, {"name":"WirelessSubwoofer","value":"AAAAAgAAAMQAAAB+Aw=="} ] ]]) function printIrCode() for i in pairs(irCode) do print(irCode[i].name) end end function irCodeLookup(irName) for i in pairs(irCode) do if (irCode[i].name == irName) then return irCode[i].value end end end -- Escape string to make suitable for embedding in HTML. function htmlize(s) s = s:gsub('&', '&') s = s:gsub('<', '<') s = s:gsub('>', '>') return s end --Helper for priniting nested table function deep_print(tbl) if (type(tbl) == "table") then for i, v in pairs(tbl) do if type(v) == "table" then deep_print(v) else print(i, v) end end else print(htmlize(tbl)); end end local successCallback = function(resp) print('At ' .. os.date() .. ' - status = ' .. resp.status) deep_print(resp.data) end local errorCallback = function(err) print('error = ' .. err) end function sendIrCode(name) local value = irCodeLookup(name) if (value == nil) then print('IR Code not found') return end local httpClient = net.HTTPClient(); httpClient:request('http://'..ip..':'..port..'/sony/IRCC', { success = successCallback, error = errorCallback, options = { method = 'POST', headers = { ['Content-Type'] = 'text/xml; charset=UTF-8', ['X-Auth-PSK'] = xAuthPSK, ['User-Agent'] = 'HC2/537.36 (KHTML, like Gecko)', ['SOAPACTION'] = '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"' }, data = [[<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1"><IRCCCode>]]..value..[[</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>]] } }); end local value = fibaro:getGlobalValue("cmd_sony_tv"); if (string.len(value) > 0) then print(''..value) sendIrCode(value) end _ Renseigner l'adresse IP de votre TV dans la scène. _ Importer le VD : Telecommande_Sony_TV.vfib _ Noter l"ID de la scène créée et renseigner l'id pour chaque bouton du VD dans la ligne : fibaro:startScene(4); Il est possible d'ajouter des boutons supplémentaires (se référer aux commandes qui se trouvent au début de la scène). J'ai mis les fonctions principales dont je me sers le plus souvent donc libre à vous de personnaliser votre télécommande en fonction de vos besoin. Je tiens à remercier @Krikroff pour son aide et sa dispo Toujours prêt à rendre service notre Jc.
  12. IPX800 V4 : Utilisation du mode Push sur un VD Contexte : Après avoir galère pour trouver un Tuto sur le Forum expliquant comment utiliser le mode push sur un IPX800 V4 pour interagir avec un Virtual Device, je partage avec vous mon cas d'usage que vous pourrez adapter selon vos besoins. Mon exemple est de pouvoir détecter une présence via des modules de détection de mouvements qui sont raccordés en mode filaire sur mon IPX800 V4. Dans mon contexte, il s'agit de détecteur Paradox DG85 pour lesquels j'associe un VD à chacun de mes détecteurs. Dans un premier temps, j'utilise ces VD pour signaler, lors d'une détection de mouvement, un message vocal sur une enceinte SONOS en mode TTS. Pré-requis : Disposer d'une HC2 pour pouvoir scripte en LUA Disposer d'un IPX800 V4 raccordé à la HC2 Disposer de détecteurs de mouvements filaires raccordés correctement sur une entrées digitale de l'IPX Disposer éventuellement une enceinte Sonos, si vous souhaitez envoyer des message vocaux. Vérifier lors de tests de mouvement devant les capteurs, que la console de l'IPX remonte bien sur le dashboard les détections. Le voyant correspondant à l'entrée doit s'éteindre lors d'une détection. Actions à réaliser sur la HC2 : 1) Charger et configurer le VD qui sera utiliser pour donner le statut du détecteur de mouvement et générer un événement qui sera intercepté par la scène de traitement des alertes vocales. Qui elle-même transmettra une message vocale à votre enceinte SONOS ou tout autre traitement qui doit découler d'une détection. Charger le VD (Détecteur Entrée) Détecteur_Entrée.vfib.json Renommer votre VD et préciser sa localisation (Exemple : Détecteur Entrée situé devant le Portail) Repérer l'identifiant du VD (dans la barre d'adresse de votre explorateur). Il vous sera utile plus tard Changer les 2 icônes ci-dessous et repérer leur ID (dans la barre d'adresse de votre explorateur) en faisant un clic droit et une ouverture de l'icônes dans une nouvel onglet, après son chargement dans votre collection icônes personnalisées. Images à modifier selon le modèle de détecteur que vous utilisez Modifier dans les propriétés avancées du VD, le code lua des boutons (Alarme) et (Normal) afin de renseigner l'ID des icônes chargées précédemment. cf. lignes ci-dessous pour le bouton (Alarme) remplace 1087 par votre ID sur le ligne ci-dessous : local IconeID = 1087 -- icône représentant une alerte d'une détection de mouvement pour le bouton (Alarme) remplace 1087 par votre ID sur le ligne ci-dessous : local IconeID = 1088 -- icône représentant une situation normale sans mouvement A faire autant que fois que de détecteurs dont vous disposez 2) Créer et configurer la scène qui va intercepté les changement d'état du VD (selon la modification du premier label dont la valeur va contenir soit Alarme, soit Normal) Dans mon cas, je vais exécuter une scène de traitement d'alertes vocales qui vont être transmises et lues par une enceinte SONOS. Si vous ne disposez pas d'une enceinte Sonos, il convient d'adapter le VD ci-dessous pour réaliser les actions que vous souhaitez intégrer dans vos cas de détections de mouvements et passer directement au chapitre Actions à réaliser sur l'IPX Créer une nouvelle scène Renommer la scène à votre convenance (Exemple : Détection Externe) Coller le code ci-dessous dans le code LUA de la Scène : --[[ %% properties 241 ui.Label1.value 242 ui.Label1.value 243 ui.Label1.value %% events %% globals --]] ---------------------------------- -- User Settings ---------------------------------- local Msg_Sonos = true local SceneID_Sonos = 61 local Volume = 20 local source = fibaro:getSourceTrigger() local id_declencheur = nil if (source["type"] == "property") then id_declencheur = tonumber(source["deviceID"]) elseif (source["type"] == "global") then id_declencheur = nil elseif (source["type"] == "other") then id_declencheur = nil end local message = nil if id_declencheur ~= nil then if fibaro:get(id_declencheur, "ui.Label1.value") == "Alarme" then if Msg_Sonos == true then if id_declencheur == 243 then message = "détection de mouvement devant la porte de garage " elseif id_declencheur == 242 then message = "détection de mouvement devant la porte dentrer a larière du jardin " elseif id_declencheur == 241 then message = "détection de mouvement a larmière du jardin " end fibaro:startScene(SceneID_Sonos, {{msg = message}, {vol = Volume}}) end deviceName = fibaro:getName(id_declencheur); roomName = fibaro:getRoomName(fibaro:getRoomID(id_declencheur)) message = string.format("Détection dans : %q sur le détecteur %q", roomName, deviceName) fibaro:debug(message .. " n° " .. id_declencheur) end else fibaro:debug("Device inconnu") end Modifier les identifiants ci-dessous (241, 242, 243) par les ID de vos VD correspondants à vos détecteurs dans la partie %% properties 241 ui.Label1.value 242 ui.Label1.value 243 ui.Label1.value Modifier le bout de code ci-dessous pour modifier les identifiants et le message qui seront envoyés à votre enceinte SONOS. if id_declencheur == 243 then message = "détection de mouvement devant la porte de garage " elseif id_declencheur == 242 then message = "détection de mouvement devant la porte dentrer a larière du jardin " elseif id_declencheur == 241 then message = "détection de mouvement a larmière du jardin " end Attention cette scène fait appel à une scène de traitement des message TTS (par passage de paramètres) qui va donner l'ordre au VD SONOS Remote d'exécuter la traduction TTS et la lecture du message. 3) Charger le VD SONOS Remote (si vous disposez d'une enceinte, sinon ignorez cette l'étape 3) Vous trouverez ci-dessous le VD SONOS Remote qui permet de piloter des enceintes SONOS créé par Jean-Christophe Vermandé SONOS_Remote.vfib.json Changer le VD ci-dessus (sauf si vous en disposé déjà) Modifier éventuellement l'icônes par celle ci-dessous Repérer l'ID de ce VD 4) Créer la scène SONOS qui traite les messages vocaux à envoyer au VD SONOS Remote (si vous en disposez, sinon ignorez cette l'étape 4) Cette scène utilise la fonction fibaro:startScene avec passage des paramètres (utile pour limiter la redondance de code et sa maintenance) Créer une nouvelle scène Renommer la scène à votre convenance (Exemple : Send Sonos Message) Modifier éventuellement l'icônes par celle chargée ci-dessus Coller le code ci-dessous dans le code LUA de la scène : --[[ %% properties %% events %% globals --]] ----------------------------------------------------------------------------- -- This Scene send a TTS mmessage on Sonos speaker ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- Params args to this Virtual Device : -- msg = message text to transforme in TTS -- vol = volume level on the Sonos Speaker ----------------------------------------------------------------------------- -- Usage exemple : -- fibaro:startScene(SceneID_Sonos, {{msg = "move detection in the garden"}, {vol = 50}}) -- SceneID_Sonos = the ID off this Virtual Device ----------------------------------------------------------------------------- -- User variables : -- sid = the Sonos Virtual Device ID -- bid = the Process button ID in then Sonos Virtual Device -- TTS_language = language off the TTS transformation ------------------------------------------------------------------------------- local sid, bid = 174, 28 local TTS_language = "fr-FR" ------------------------------------------------------------------------------- -- DO not change bellow this line ------------------------------------------------------------------------------- local params = fibaro:args() if (params) then for k, v in ipairs(params) do if (v.msg) then msg = v.msg end if (v.vol) then vol = v.vol end end fibaro:debug("Message : "..msg.." Vol = "..vol) -- Create TTS params object local params = { -- TTS Message message = msg, duration = 'auto', -- Duration: "auto", xx seconds language = TTS_language, -- Language: fr-FR volume = vol -- Volume } fibaro:debug("Message : "..params.message.." Vol = "..params.volume) local _f = fibaro local _x ={root="x_sonos_object", load=function(b) local c=_f:getGlobalValue(b.root) if string.len(c)>0 then local d=json.decode(c) if d and type(d)=="table"then return d else _f:debug("Unable to process data, check variable") end else _f:debug("No data found!") end end, set=function(b,e,d) local f=b: load() if f[e]then for g,h in pairs(d) do f[e][g]=h end else f[e]=d end; _f:setGlobal(b.root,json.encode(f)) end, get=function(b,e) local f=b: load() if f and type(f)=="table"then for g,h in pairs(f) do if tostring(g)==tostring(e or"") then return h end end end; return nil end } -- Make a request to the remote to process params object instantly _x:set(tostring(sid), { tts = params }) _f:call(sid, "pressButton", bid) else fibaro:debug("Pas de message") end Modifier l'identifiant ci-dessous 174 (sid) qui correspond à l'ID VD de votre SONOS Remote (repéré à l'étape précédente) Modifier la valeur 28 (bid) qui correspond au nième object de votre VD SONOS Remote et correspondant au bouton (Process) ----------------------------------------------------------------------------- -- User variables : -- sid = the Sonos Virtual Device ID -- bid = the Process button ID in then Sonos Virtual Device -- TTS_language = language off the TTS transformation ------------------------------------------------------------------------------- local sid, bid = 174, 28 local TTS_language = "fr-FR" Actions à réaliser sur l'IPX : 1) Configurer l'entrée digitale correspondante au détecteur raccordé Sur le dashboard cliquer sur l'options (PERIPHERIQUES) Puis cliquer sur (ENTRÉES DIGITALES) Donner un nom (exemple sur l'entrée 2 : Détecteur Ext. Entrée Portail) en claire correspondant à l'entée sur laquelle vous avez raccordé votre détecteur 2) Configurer l'action PUSH qui va interagir avec le VD de la HC2 correspondant au détecteur de mouvement créé précédemment Sur le dashboard cliquer sur l'options (PERIPHERIQUES) Puis cliquer sur (PUSH) Sélectionner une action PUSH non utilisée (cliquer sur la ligne correspondante), voir exemple ci-dessous Donner un NOM (exemple : Mvt Ent. Portail) en claire Renseigner le SERVEUR, soit l'adresse IP de votre HC2 (exemple : 192.168.0.33) Renseigner le PORT sur laquelle, votre HC2 est joignable (exemple : 80 dans mon cas) Renseigner l'IDENTIFIANT, soit le nom de l'utilisateur et son mot de passe avec 2 points superposé entre les 2. (exemple : USER:PSW) Renseigner URL ON, soit la commande qui sera passée à la HC2 lorsque la détection de mouvement sera terminée. Qui va provoquer un clic sur le premier bouton (Normal) du VD. /api/callAction?deviceID=243&name=pressButton&arg1=4 remplacer le n°243 par l'ID de votre VD pour info 4 correspond au quatrième objet du VD, soit le bouton (Normal) Renseigner URL OFF, soit la commande qui sera passée à la HC2 lorsque la détection d'un mouvement. Qui va provoquer un clic sur deuxième le bouton (Alarme) du VD. /api/callAction?deviceID=243&name=pressButton&arg1=3 remplacer le n°243 par l'ID de votre VD pour info 3 correspond au troisième objet du VD, soit le bouton (Alarme) Renseigner METHODE par la valeur GET Renseigner SSL par la valeur OFF (pour le moment je n'ai pas encore trouver comment passer les commandes en mode SSL (HTTPS) afin de crypter la commande sur la trame réseau, notamment le mot de passe) Puis cliquer sur (SAUVEGARDER) puis (RETOUR), voir exemple ci-dessous 3) Configurer un scenario qui va lancer le PUSH définit précédemment Sur le dashboard cliquer sur l'options (SCENARIO) Puis cliquer sur (LISTE DES SCÈNES) Sélectionner une scène non utilisée (cliquer sur la ligne correspondante), voir exemple ci-dessous Donner un nom à la Scène (Mouvement Entrée Portail), dans la ligne intitulée NOM, voir exemple ci-dessous Dans la partie (EVENEMENT) du scénario, il convient d'ajouter l'entrée digitale correspondante au Détecteur définit précédemment par un glisser/déplacer du bouton (ENTREE DIGITALE) dans la zone EVENEMENT Puis une sélection dans liste disponible sur la ligne intitulé (NUMERO) Puis cliquer sur (SAUVEGARDER) puis (RETOUR) Dans la partie (ACTION) du scénario, il convient de définir la valeur (ON/OFF) par un glisser/déplacer du bouton (ON/OFF) dans la zone ACTION Dans la partie (RESULTAT) du scénario, il convient d'ajouter une action (PUSH) par un glisser/déplacer du bouton (PUSH) dans la zone RESULTAT Puis cliquer sur le bouton (PUSH) ajouté Puis sélectionner dans liste, le Push créé précédemment disponible sur la ligne intitulé (NUMERO) Puis cliquer sur (SAUVEGARDER) puis (RETOUR) Recommencer cette opération autant de fois que de détecteurs à configurer. Actions à réaliser sur votre HC2 : Vous promener devant vos détecteurs avec votre ordinateur portable (si vous en disposez, sinon votre téléphone, tablette) Vérifier le bon fonctionnement : de vos VD correspondants a vos détecteurs (les icônes doivent changer a chaque détection et fin de détection de mouvement) écouter sur votre enceinte SONOS le bon envoi des messages TTS Corriger les éventuels bugs Me demander éventuellement des explications ou support sur ce Tuto Adapter ce Tuto selon vos besoins d'utilisation de la fonction PUSH de votre IPX800 V4 et son interaction avec votre HC2
  13. Je vous partage mon script que j'ai créer pour être régulièrement notifié de ma production photovoltaà¯que. A savoir que ce script est facilement adaptable pour suivre sa consommation Electrique générale compteur + coà»t Petit rappel pour récupérer les valeur de l'écodevice et envoyer cela dans des variables : HC2 = Net.FHttp("192.168.0.151")-- ip de l'écodevice response = HC2:GET("/api/xdevices.json?cmd=10") -- enregistrement du retour de l API dans une table response = json.decode(response) fibaro:setGlobal("ABO", response.T1_PTEC) fibaro:setGlobal("CONSO", response.T1_PAPP) fibaro:setGlobal("IHP", response.T1_HCHP) fibaro:setGlobal("IHC", response.T1_HCHC) fibaro:setGlobal("PROD", response.T2_PAPP) fibaro:setGlobal("INDEXPROD", response.T2_BASE) fibaro:log(fibaro:getGlobalValue("CONSO").." W Tarif : "..fibaro:getGlobalValue("ABO").." Index HP : "..fibaro:getGlobalValue("IHP").." Index HC :" ..fibaro:getGlobalValue("IHC") ) Tout d'abord, il va falloir créer 4 variables globales: -index ( index relevé à minuit ) -indexprod ( index à l'instant "t" ) -indexmois ( index relevé le 1er du mois ) -index28/07 ( index relevé à la date du contrat erdf ) J'ai crée un vd avec 4 boutons, 3 boutons renseignent donc ces variables à des moments précis --récupération de l'index de production local indexprod = fibaro:getGlobal("INDEXPROD") fibaro:debug(indexprod) --affectation de la prod dans la var "index" / a faire à minuit fibaro:setGlobal("index", indexprod); --récupération de l'index de production local indexprod = fibaro:getGlobal("INDEXPROD") fibaro:debug(indexprod) --affectation de la prod dans la var "indexmois" / a faire au 1er du mois fibaro:setGlobal("indexmois", indexprod); --recupération de l'index de production local indexprod = fibaro:getGlobal("INDEXPROD") fibaro:debug(indexprod) --affectation de la prod dans la var "index2807" / a faire à la date souhaitée fibaro:setGlobal("index2807", indexprod); Le dernier bouton servant à faire les relevés d'index et calcul : -- Formattage des chiffres --- function formatIndex(value) local sous = (indexprod - value)/1000;--soustraction return string.format("%010.3f", sous) end indexprod = tonumber(fibaro:getGlobal("INDEXPROD") or 0); fibaro:debug("index actuel: "..indexprod.."");--récup prod actuelle local index = tonumber(formatIndex(tonumber(fibaro:getGlobal("index") or 0))); local minuit = tonumber(fibaro:getGlobal("index") or 0); fibaro:debug("index à minuit: "..minuit.."");--récup prod à minuit local indexmois = tonumber(formatIndex(tonumber(fibaro:getGlobal("indexmois") or 0))); local mois = tonumber(fibaro:getGlobal("indexmois") or 0); fibaro:debug("index au 1er: "..mois.."")--récup prod du mois local index2807 = tonumber(formatIndex(tonumber(fibaro:getGlobal("index2807") or 0))); local date = tonumber(fibaro:getGlobal("index2807") or 0); fibaro:debug("index au 28/07: "..date.."")--récup prod à la date choisie local euro = tonumber(0.465)--prix d'achat erdf --------------- local prixjour = (euro * index) jour = string.sub(prixjour, 1, 4) --fibaro:debug(jour) fibaro:debug("Prod du jour : "..index.." Kwh - soit: "..jour.." €"); ------------- local prixmois = (euro * indexmois) mois = string.sub(prixmois, 1, 6) --fibaro:debug(mois) fibaro:debug("Prod du mois : "..indexmois.." Kwh - soit: "..mois.." €"); ------------- local prixannee = (euro * index2807) annee = string.sub(prixannee, 1, 7) --fibaro:debug(annee) fibaro:debug("Prod depuis le 28/07 : "..index2807.." Kwh - soit: "..annee.." €"); ------------- message = ("Production solaire du jour : "..index.." Kwh - soit: "..jour.." € / Production mensuelle : "..indexmois.." Kwh - soit: "..mois.." € / Production annuelle :"..index2807.." Kwh - soit: "..annee.." €") fibaro:debug(message); fibaro:setGlobal("pushover", message); fibaro:call(198, "pressButton", "2"); --pushover lua fibaro:sleep(1000); fibaro:setGlobal("pushover", "" );--raz variable En "debug" : [DEBUG] 18:19:32: index actuel: 8715878 [DEBUG] 18:19:32: index à minuit: 8698402 [DEBUG] 18:19:32: index au 1er: 8485402 [DEBUG] 18:19:32: index au 28/07: 6340400 [DEBUG] 18:19:32: 8.12 [DEBUG] 18:19:32: Prod du jour : 17.476 Kwh - soit: 8.12 € [DEBUG] 18:19:32: 107.17 [DEBUG] 18:19:32: Prod du mois : 230.476 Kwh - soit: 107.17 € [DEBUG] 18:19:32: 1104.59 [DEBUG] 18:19:32: Prod depuis le 28/07 : 2375.478 Kwh - soit: 1104.59 € [DEBUG] 18:19:32: Production solaire du jour : 17.476 Kwh - soit: 8.12 € / Production mensuelle : 230.476 Kwh - soit: 107.17 € / Production annuelle :2375.478 Kwh - soit: 1104.59 € Personnellement, j'ai choisi d’être informé 2 fois par jour avec l'application "pushover". J'ai donc créé une scène qui "appui" sur le bouton n°4 et qui me notifie quotidiennement ma production :
  14. Hello, Pour changer des scripts et autres paramètres de configuration, je vous propose du bricolage Ce tutoriel décrit en image comment réaliser des fausses piles en bois, destinées à remplacer les vraies piles de nos appareils électroniques qui ont une fâcheuse tendance à se décharger bien trop vite, surtout pour les équipements Z-Wave telles que les sondes de températures. Contrairement à une alimentation soudée, ces fausses piles permettent de conserver la garantie de l'appareil alimenté. Bien sûr, pour que cela fonctionne, il faut que l'appareil à alimenter sur secteur puisse se satisfaire d'un fil à la patte, ce qui peut nécessiter le passage d'une gaine encastrée dans le mur afin de conserver un WAF acceptable. Pour commencer, un tour sur Wikipédia nous permet de trouver les dimensions des piles standards. Ce tuto décrit la réalisation d'une fausse pile AA, ayant pour longueur 50 mm et pour diamètre 14,2 mm. On peut bien entendu réaliser de la même façon des piles AAA, ou tout autre format. Dans notre magasin de bricolage préféré, on cherche des tourillons du bon diamètre. Je n'ai pas trouvé de 14mm, alors je me rabat sur du 12mm. C'est vendu au mètre. Il est fortement conseillé de disposer d'une boite à onglet pour guider la scie : On découpe une longueur d'environ 45mm afin de laisser de la place pour la tête de vis. On notera que j'ai fait le choix de prendre des vis à tête hexagonale, car elles ont une tête plate, ce qui permettra un meilleur contact dans le logement des piles : A l'aide d'un forêt à bois de diamètre 3mm, on perce dans la longueur du tourillon. Si on ne dispose pas d'une perceuse à colonne, ce n'est pas évident de rester aligné dans l'axe. Il est indispensable de bloquer le tourillon dans un étau : A l'aide d'un forêt de 8mm environ, on perce cette fois-ci un trou sur le coté afin de récupérer l'autre extrémité de la vis lorsque celle-ci sera en place. Attention à ne pas traverser complètement le tourillon, ce qui fragiliserait le tourillon inutilement : La vis en place : On prend ensuite du fil électrique multibrin, de préférence rouge (positif) et noir (masse) afin de respecter les conventions. J'utilise du fil électrique qu'on trouve en magasin automobile en petite bobine. La section est très largement surdimensionnée pour le très faible courant qu'on va faire passer dedans. Il y a 2 solutions possibles pour fixer le fil sur la vis : - fil noir : souder un gros paquet d'étain, en prenant soin de ne pas cramer le bois - fil rouge : j'ai réalisé le trou de 8mm plus près du bord, ainsi la vis traverse intégralement le trou. Ensuite, en vissant, le fil s'entortille tout autour. Les 2 piles sont prêtes. Il faut maintenant trouver une alimentation secteur correspondant à la tension des piles. Dans cet exemple j'utilise un vieux chargeur, qu'on relie comme on peut à nos fils. Ce n'est pas propre, je proposerai peut-être dans la futur comment réaliser une alimentation sérieuse. Ce chargeur délivre du 5V (vérifié au multimètre), tandis que j'ai besoin de 4,5V. Cette légère surtension ne devrait pas poser de soucis à l'appareil que je vais alimenter : On met en place les 2 piles dans le logement, de telle sorte que le fil rouge alimente le coté positif, et le fil noir alimente le coté négatif. Ici il s'agit d'un Everspring ST814 : On referme si possible le capot. Je ne sert pas la vis trop fort afin de ne pas couper les 2 fils, mais une autre solution serait de faire un petit trou dans la coque, mais avec évidemment la perte de la garantie : Puisque la HC2 ne permet pas de voir le niveau de la batterie des modules, on utilise le Toolkit de Krikroff pour vérifier qu'on a une batterie chargée à 100% : { "id": 65, "name": "ST814", "roomID": 8, "type": "humidity_sensor", "properties": { "UIMessageSendTime": "0", "batteryLevel": "100", "batteryLowNotification": "1", ... } Dans mon cas, il s'agit d'un capteur qui est situé dans la cave, donc le coté esthétique de l'alimentation ne me gêne pas pour le moment. Et surtout, ce capteur m'a bouffé 3 jeux de piles en 3 mois ! C'est étonnant car mes 2 autres ST814 n'ont pas ce défaut. Maintenant, on peut baisser l’intervalle de Wake-up de device, et dans le cas d'un capteur de température/humidité, lui demander de remonter les informations à la moindre variation
  15. Je souhaitais me simplifier la vie et pouvoir confirmer un ordre par TTS sur mes squeezebox (ex l'allumage du fer à repasser depuis le second alors qu'il est au sous-sol). J'en ai 5 (Cuisine, Salon, Garage, Chambre du Haut et Chambre du Bas). J'ai donc fait un module virtuel "EmissionSqueeze" qui me permet d'émettre une phrase depuis n'importe qu'elle scène (ou bouton) en 5 lignes ! Voici le code qui vous permettra d'appeler ce module virtuel en 4 ligne depuis n'importe où : -- Faire un copier/coller de ce code dans le bouton -- depuis lequel on souhaite diffuser un message -- Le niveau sonore est attribué à chaque squeeze individuellement -- à la suite du nom avec comme valeur de 01 à 99 (pas 100 ! on doit rester sur 2 chiffres) -- SqueezeNom -> Cuisine ; Salon ; ChambreB ; ChambreH ; Garage -- Attention à ne pas se tromper sur l'orthographe des Squeezes !!! -- Messager -> Texte pour la TTS (inutile de mettre des %20) --Liste des squeezes sous la forme {"Cuisine30","Garage80","Salon60","ChambreH30","ChambreB50"} local ListeSqueeze = {"Cuisine55","Garage99","Salon60","ChambreH30","ChambreB30"} fibaro:setGlobal("SqueezeNom" , json.encode(ListeSqueeze)) -- Taper le message fibaro:setGlobal('Messager' , "Ouverture du portail") fibaro:call(144, "pressButton", "1"); -- fin annonce Squeezebox Voici le code principal du bouton 1 du module virtuel 144 : -- JossAlf ; 02/07/14 (V2.1) 21/06/14 (V2.0) 17/06/14 (V1.3) ; 22/05/14 (V1.1) ; 23/05/14 (V1.2) -- V2.1 : Ajout du réglage individuel duniveau sonore pour chaque squeeze en ajoutant 2 chiffre après le nom -- V2.0 : Simplification du code et possibilité d'allumer 1,2,3,4 ou 5 squeeze. -- Scène permettant simplifier la diffusion de messages sur 1 ou plusieurs squeezeboxes. -- Nécessite de créer les Variables Globales : SqueezeNom ; Messager -- (Ne pas utiliser dans une scène le json bug) -- l'appel de module virtuel se fera dans un autre module virtuel de façon simple -- en affectant les valeurs aux variables Globales -- puis en simulant le clic sur un bouton : exemple -> fibaro:call(144, "pressButton", "1"); local ListeSqueeze = fibaro:getGlobal("SqueezeNom"); local TableauSqueezeNom = json.decode(ListeSqueeze); local player = nil -- Adresse IP du Logitech Media Server local ipadd = "192.168.0.46" -- le port du serveur local portno = 9090 local Squeezers = { ['Cuisine'] = "00:04:xx:xx:xx:00 ", ['Salon'] = "00:04:xx:xx:xx:3e ", ['ChambreB'] = "00:04:xx:xx:xx:fe ", ['ChambreH'] = "00:04:xx:xx:xx:ba ", ['Garage'] = "00:04:xx:xx:xx:bc ", } --On allume toutes les squeezes for i = 1, #TableauSqueezeNom do --on récupère uniquement le nom en retirant les 2 derniers caractères qui correspondent au niveau sonore local player = string.sub(TableauSqueezeNom[i], 1 , -3) fibaro:debug(player) local player = Squeezers[player] local cmnd = "power 1 " local stringtosend = player .. cmnd .. string.char(10) tcpSocket = Net.FTcpSocket(ipadd, portno) tcpSocket:setReadTimeout(2*1000) bytes, errorCode = tcpSocket:write(stringtosend) -- on règle le son -- on prend que les 2 dernier caractères qui correspondent au niveau sonore. local VolumeSon = string.sub(TableauSqueezeNom[i], -2) local cmnd = "mixer volume " .. VolumeSon .. " " local stringtosend = player .. cmnd .. string.char(10) tcpSocket = Net.FTcpSocket(ipadd, portno) tcpSocket:setReadTimeout(2*1000) bytes, errorCode = tcpSocket:write(stringtosend) end -- on laisse une seconde pour laisser le temps à toutes les squeeze de s'allumer fibaro:sleep(1000) -- On envoie le message en utilisant la première radio local player = string.sub(TableauSqueezeNom[1], 1 , -3) local player = Squeezers[player] local notification = fibaro:getGlobalValue('Messager') -- On remplace les espaces par des %20 local notification = string.gsub((notification)," ", "%%20"); fibaro:debug(notification) -- Attention google ne fonctionne plus il vaut mieux utiliser VoiceRSS pour le TTS -- local cmnd = "playlist play http://translate.google.com/translate_tts?tl=FR&ie=UTF-8&q=" .. notification; -- Voicerss TTS local cmnd = "playlist play http://www.voicerss.org/controls/speech.ashx?hl=fr-fr&src=" .. notification; local stringtosend = player .. cmnd .. string.char(10) tcpSocket = Net.FTcpSocket(ipadd, portno) tcpSocket:setReadTimeout(2*1000) bytes, errorCode = tcpSocket:write(stringtosend) -- OFF des squeezeBoxs après 10 secondes fibaro:sleep(20*1000) -- on éteint les squeezes for i = 1, #TableauSqueezeNom do fibaro:debug("debut de la boucle") local player = string.sub(TableauSqueezeNom[i], 1 , -3) local player = Squeezers[player] local cmnd = "power 0 " local stringtosend = player .. cmnd .. string.char(10) tcpSocket = Net.FTcpSocket(ipadd, portno) tcpSocket:setReadTimeout(2*1000) bytes, errorCode = tcpSocket:write(stringtosend) end MAJ : Simplification du code avec une boucle et le passage des "paramètres" sous forme de variable traduite en tableau en passant par un json. On peux maintenant choisir d'émettre sur une ou plusieurs radio en les nommants. Attention à bien renseigner le nom de votre squeeze avec le niveau sonore collé (exemple "Cuisine80") si non ... Pour la diffusion d'un message/fichier MP3, se référer au message 20 de ce sujet. PS : Merci à Steven pour le coup du Json (pour obtenir un tableau) et pour Shad et la boucle "for". MAJ2 : Evolution du code afin de choisir individuellement le niveau sonore des squeezer. MAJ3 : Google ne fonctionne plus en lien directe (à la ligne 62) Je l'ai remplacé par VoiceRSS (ligne 65) qui fait très bien le travail http://www.voicerss.org/controls/speech.ashx?hl=fr-fr&src= J'en parle ici : #80
  16. Moicphil

    Téléinfo avec Eco-Device

    Si comme moi, vous souhaitez gérer la ou les sorties téléinfo de votre compteur pour monitorer cela sur la HC2, ce tutoriel est fait pour vous... Même si l'Eco-device possède son propre serveur, l''intégrer à la HC2 m'est très utile comme par exemple, déclencher la machine à laver automatiquement dés le passage en Heure Creuse, ou connaitre la conso instantanée de votre domicile.... Sachez qu'il est possible d'aller plus loin comme enregistrer les données, générer des graphes...etc... Tutoriel : http://domotique-info.fr/2013/06/suivi-energetique-eco-device-et-fibaro/ Test de l'eco-device : http://domotique-info.fr/2013/06/test-eco-devices-suivre-vos-consommations/
  17. Shad

    Association De Module

    Associations des Modules Ce tutoriel à pour but d'expliquer comment associer efficacement des modules entre eux tous en évitant de faire des changements d'états inutiles. Pour quoi éviter les associations avec la Fibaro: Trop fouillis pour moi Faut une bonne mémoire pour ce rappeler de toutes les associations Peut-être difficile à débugger en cas de problème 1- Pour commencer l'entête du script, on y mettra les ID qui doivent démarrer la scène: --[[ %% properties 12 value 50 value 60 value 64 value %% globals --]] 2- On définie nos locals et nos modules : local startSource = fibaro:getSourceTrigger(); --Settings debug = "no"; --IdDevice lightMasterBathRoom = 12; ledMasterBathRoom = 26; rgbwMasterBathRoom = 30; lightKitchen = 60; lightSalleManger = 64; lightSalleManger2 = 62; spotKitchen = 88; lightRoom2 = 50; light2Room2 = 52; La fonction debug affichera en rouge un turnOn, en bleue un turOn, en vert un valeur et en orange la valeur et l'id de lu module de commande 3- La fonction qui permet d'éviter les changements d'états inutile. function StateDevice (typeDevice, idDevice, valueDevice) if (typeDevice == "contactDevice") then if (valueDevice == "turnOff") then if ( tonumber(fibaro:getValue(idDevice, "value")) == 1) then fibaro:call(idDevice, "turnOff"); if (debug == "yes") then fibaro:debug("<font color='blue'>Id: " .. idDevice .. ", value: TurnOff</font> "); end end elseif (valueDevice == "turnOn") then if ( tonumber(fibaro:getValue(idDevice, "value")) == 0) then fibaro:call(idDevice, "turnOn"); if (debug == "yes") then fibaro:debug("<font color='red'>Id: " .. idDevice .. ", value: TurnOn </font> "); end end end end if (typeDevice == "RgbwDevice") then if (valueDevice == "turnOff") then if ( tonumber(fibaro:getValue(idDevice, "value")) ~= 0) then fibaro:call(idDevice, "turnOff"); if (debug == "yes") then fibaro:debug("<font color='blue'>Id: " .. idDevice .. ", value: TurnOff </font> "); end end elseif (valueDevice == "turnOn") then if ( tonumber(fibaro:getValue(idDevice, "value")) == 0) then fibaro:call(idDevice, "turnOn"); if (debug == "yes") then fibaro:debug("<font color='red'>Id: " .. idDevice .. ", value: TurnOn </font> "); end end end end if (typeDevice == "DimmerDevice") then if (valueDevice == "turnOn" or valueDevice == "turnOff") then if (valueDevice == "turnOff") then if ( tonumber(fibaro:getValue(idDevice, "value")) ~= valueDevice) then fibaro:call(idDevice, "turnOff"); if (debug == "yes") then fibaro:debug("<font color='blue'>Id: " .. idDevice .. ", value: TurnOff </font> "); end end elseif (valueDevice == "turnOn") then if ( tonumber(fibaro:getValue(idDevice, "value")) == valueDevice) then fibaro:call(idDevice, "turnOn"); if (debug == "yes") then fibaro:debug("<font color='red'>Id: " .. idDevice .. ", value: TurnOn </font> "); end end end elseif ( tonumber(fibaro:getValue(idDevice, "value")) ~= valueDevice) then fibaro:call(idDevice, "setValue", valueDevice); if (debug == "yes") then fibaro:debug("<font color='green'>Id: " .. idDevice .. ", value: " .. valueDevice .. " </font> "); end end elseif (typeDevice == "contactBlind") then if (valueDevice == "Close" or valueDevice == "Open") then if (valueDevice ~= "Close") then if ( tonumber(fibaro:getValue(idDevice, "value")) ~= 0) then fibaro:call(idDevice, "close"); if (debug == "yes") then fibaro:debug("<font color='blue'>Id: " .. idDevice .. ", value: Fermé </font> "); end end elseif (valueDevice == "Open") then if ( tonumber(fibaro:getValue(idDevice, "value")) ~= 99) then fibaro:call(idDevice, "open"); if (debug == "yes") then fibaro:debug("<font color='red'>Id: " .. idDevice .. ", value: Ouvert </font> "); end end end elseif ( tonumber(fibaro:getValue(idDevice, "value")) ~= valueDevice) then fibaro:call(idDevice, "setValue", valueDevice); if (debug == "yes") then fibaro:debug("<font color='green'>Id: " .. idDevice .. ", value: " .. valueDevice .. " </font> "); end end end end La fonction StateDevice a besoin de 3 paramètres: typeDevice qui a pour valeur: contactDevice/RgbwDevice/DimmerDevice/contactBlind idDevice: l'id du device qu'il faut modifier l'état valueDevice qui a pour valeur: turnOn/turnOff/Close/Open/0-99 Attention, vue qu'il y a un problème pour les volets avec la box, le contactBlind ne fonctionne pas. 4- Et pour finir on met notre code d'associations: if (startSource['type']=='property') then if (debug == "yes") then fibaro:debug("<font color='green'>Id:" .. startSource['deviceID'] .. ", value: " .. tonumber(fibaro:getValue(startSource['deviceID'], "value")) .. "</font> "); end -- Lumière salle de bain Master if (startSource['deviceID'] == lightMasterBathRoom) then if ( tonumber(fibaro:getValue(lightMasterBathRoom, "value")) == 99 ) then StateDevice ("contactDevice", ledMasterBathRoom, "turnOn"); StateDevice ("RgbwDevice", rgbwMasterBathRoom, "turnOn"); elseif ( tonumber(fibaro:getValue(lightMasterBathRoom, "value")) <= 95 ) then StateDevice ("contactDevice", ledMasterBathRoom, "turnOff"); StateDevice ("RgbwDevice", rgbwMasterBathRoom, "turnOff"); end elseif (startSource['deviceID'] == lightKitchen) then if ( tonumber(fibaro:getValue(lightKitchen, "value")) == 99 ) then StateDevice ("contactDevice", spotKitchen, "turnOn"); elseif ( tonumber(fibaro:getValue(lightKitchen, "value")) < 99 ) then StateDevice ("contactDevice", spotKitchen, "turnOff"); end elseif (startSource['deviceID'] == lightRoom2) then if ( tonumber(fibaro:getValue(lightRoom2, "value")) == 99 ) then --StateDevice ("contactDevice", spotKitchen, "turnOn"); fibaro:call(52, "setValue", "99") elseif ( tonumber(fibaro:getValue(lightRoom2, "value")) < 99 ) then --StateDevice ("contactDevice", spotKitchen, "turnOff"); fibaro:call(52, "setValue", "0") end elseif (startSource['deviceID'] == lightSalleManger) then StateDevice ("DimmerDevice", lightSalleManger2, fibaro:getValue(lightSalleManger, "value")); end end Je vous ai mis qu'une partie de mon code pour voir un peu le fonctionnement. Amusez-vous bien.
  18. Bonjour, Voici le module virtuel pour l'ECO-DEVICES que je souhaitais faire pour afficher mes consommations mensuelles directement sur le HC2. Je n'ai pas traité le main loop pour le moment donc si vous souhaitez l'améliorer, pas de soucis. Il affiche : • la consommation HP/HC de chaque mois • le coà»t associé pour chaque mois (hors abo) Ce module est prévu pour un abonnement HP/HC mais vous pourrez l'adapter facilement en changeant le pattern qui parse le fichier CSV. Le données sont stockées dans une variable energylist. Il faut la créer dans le panneau Variables. Voilà ce que ça donne sur Androà¯d. Il reste à traiter les points suivants : envoyer de rapports quotidiens via Pushover comparaison de la conso à M-1 automatiser le chargement des valeurs à 00h05 chaque jour via le main loop Consos_mois 1.1.2.vfib
  19. Voici un module virtuel pour l'ECO-DEVICES. J'ai utilisé un bouton plutôt que le main loop car au bout de quelques heures/jours les informations ne remontaient plus. J'espère que ça tiendra cette fois (c'est ok depuis 3 jours)... Il affiche : • l'index en temps réel (évite de descendre dans le garage pour le relevé compteur ou de le faire pendant les vacances) • la consommation instantanée en kWh • la consommation depuis 00h01 et le coà»t en euros. Pour ce calcul, je vous invite à vérifier vos coà»t, taxe et abonnement sur votre facture. Ce module est prévu pour un abonnement standard (donc sans HP HC) mais vous pourrez l'adapter facilement. La conso de la veille est la même sur l'image car je viens de la créer. Elle sera mise à jour ce soit à 00h01. Il vous faudra créer 5 variables globales dans le panneau variables : • ABO • CONSO • INDEX • ConsoMinuit • ConsoVeille Voici le main loop (réduit à sa plus simple expression mais commenté !) -- Notez l'utilisation d'un bouton et non du main loop qui plante au bout de quelques heures !!! -- Pensez à modifier l'adresse IP de votre ECO-Devices. -- NB : calcul commencera seulement après 00h01 (heure de la Mà J de la velur de l'index de référence) fibaro:call(63, "pressButton", "6"); fibaro:sleep(5*1000) -- Attention HC2 ajoute à ce temps le loop de 3 secondes par défaut. Voici le code du bouton (ID 6) : -- mise à jour des données en provenance de l'ECO-Devices : HC2 = Net.FHttp("192.168.0.53") response = HC2:GET("/api/xdevices.json?cmd=10") -- enregistrement du retour de l API dans une table fibaro:debug(response) response = json.decode(response) fibaro:setGlobal("ABO", response.T1_PTEC) fibaro:setGlobal("CONSO", response.T1_PAPP) fibaro:setGlobal("INDEX", response.T1_BASE/1000) fibaro:call(63, "setProperty", "ui.Label1.value", fibaro:getGlobalValue("INDEX") .. " kWh") fibaro:call(63, "setProperty", "ui.Label2.value", fibaro:getGlobalValue("CONSO").." Watts") -- Calcul du coà»t de la conso de la journée maintenant : local VconsoInstant = (fibaro:getGlobalValue("INDEX") - fibaro:getGlobalValue("ConsoMinuit")) VconsoInstant = string.format("%.2f",VconsoInstant) -- coà»t conso réelle (sans abo et taxes) local Vcout = (VconsoInstant * 0.105) -- Prix unitaire HT (€/kWh) :0,0883 HT -- 0,60 € c'est le coà»t TTC des taxes et abonnement : abo + TCFE (CR*0,00932) + CSPE (CR*0,01650) + CTA 2,88 local AboTaxeEtContribution = (15.78 + (VconsoInstant*0.00932) + (VconsoInstant*0.01650) +2.88)/30 --AboTaxeEtContribution = string.format("%.3f",AboTaxeEtContribution) -- calcul conso intstantanée + cout frais fixes à la journée Vcout = Vcout + AboTaxeEtContribution -- réduction du nombre de chiffre après la virgule : Vcout = string.format("%.2f",Vcout) -- Sauvegarde de la conso de la veille : local currentDate = os.date("*t"); if ( ( ((currentDate.wday == 1 or currentDate.wday == 2 or currentDate.wday == 3 or currentDate.wday == 4 or currentDate.wday == 5 or currentDate.wday == 6 or currentDate.wday == 7) and string.format("%02d", currentDate.hour) .. ":" .. string.format("%02d", currentDate.min) == "00:00") ) ) then fibaro:setGlobal("ConsoVeille", VconsoInstant .. " kWh soit " .. Vcout .. " €") end -- Sauvegarde de l'index à minuit une : if ( ( ((currentDate.wday == 1 or currentDate.wday == 2 or currentDate.wday == 3 or currentDate.wday == 4 or currentDate.wday == 5 or currentDate.wday == 6 or currentDate.wday == 7) and string.format("%02d", currentDate.hour) .. ":" .. string.format("%02d", currentDate.min) == "00:01") ) ) then fibaro:setGlobal("ConsoMinuit", fibaro:getGlobalValue("INDEX")) end -- mise à jour des valeurs des labels fibaro:call(63, "setProperty", "ui.Label3.value", fibaro:getGlobalValue("ConsoMinuit")) fibaro:call(63, "setProperty", "ui.Label4.value", VconsoInstant .. " kWh = " .. Vcout .. " €") fibaro:call(63, "setProperty", "ui.Label5.value", fibaro:getGlobalValue("ConsoVeille")) N'hésitez pas si vous avez des questions ... Mà J : Avec la conso de la veille ... EDF_Ecodevices.vfib
×