Aller au contenu

Rechercher dans la communauté

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



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

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

103 résultats trouvés

  1. idomotique

    Notification en LUA sur HC3

    Bonjour a tous, voici un modeste petit tuto pour envoyer des notifications en LUA sur une HC3 Notification Simple Explication Les notification simples peuvent être envoyés par push ou par email à un ou plusieurs utilisateurs. Il s'agit uniquement d'une information pour le/les utilisateurs. Aucune réponse n'est possible. Paramètres Cette commande comprend 3 paramètres: Type de notification push: envoyé par notification push sur les appareils mobiles configurés dans le menu accès. email :envoyé à l'adresse email associée à l'utilisateur sélectionné. Utilisateur sélectionné Un ou plusieurs utilisateurs peuvent être sélectionés. Pour cela il est nécessaire de récupérer l'ID de l'utilisateur désiré dans le menu Accès du Home center Il faut ensuite le mettre sous la forme suivante [numéro] = ID utilisateur, ou numéro correspond au nombre d'utilisateurs désirés. Message Pour finir il faut indiquer le message à afficher dans la notification Exemple Example 1 (push) Dans cet exemple on envoie une notification push à 2 utilisateurs avec les ID 2 et 809 avec le message "Alarme déclanchée" fibaro.alert('push', {[1] = 2, [2] = 809, }, 'Alarme déclanché') Example 2 (Email) Dans cet exemple on envoie une notification push à 1 utilisateur avec l'ID 809 avec le message "Fausse Alarme" fibaro.alert('email', {[1] = 809, }, 'Fausse Alarme') Notification Interactive Explication Les notifications interactives ne peuvent être envoyées que par push à un ou plusieurs appareils mobiles et nécessite une réaction de l'utilisateur choisit. Paramètres Catégorie (["category"]) RUN_CANCEL : L'utilisateur aura le choix entre les réponse Run et Cancel YES_NO : L'utilisateur aura le choix entre les réponse Yes et No Titre (["title"]) Ce paramètre contiendra le titre de la notification envoyé Catégorie (["mobiledevice"]) Il est possible d'envoyer la notification à un ou plusieurs appareils. Il faut pour cela sélectionner les appareils désirés dans le menu accès du Home center. Il faut ensuite le mettre sous la forme suivante [numéro] = ID appareil, ou numéro correspond au nombre d'appareils désirés. Données(["data"]) Il s'agit de l'action effectuée lorsque l'utilisateur répond Yes ou Run. Si l'action est sur un module: ["actionName"] = "turnOn", ["deviceId"] = 545, Si l'action est sur une scène: ["sceneId"] = 133, Message(["message"]) Correspond au message indigué dans la notification. Action(["action"]) Détermine le type d'action à effectuer en fonction de si l'action se fait sur un module ou sur une scène RunAction : Si l'action est sur un Module Run : Si l'action est sur une scène Service(["service"]) Permet de définir si l'action sera sur un module ou sur une scène Device : Si l'action est sur un Module Scene : Si l'action est sur une scène Exemple Exemple 1: activation d'une lumière Dans cet exemple on demande à l'utilisateur si il désire activer une lampe lorsque le mauvais code d'entrée est tapé. api.post("/mobile/push", { ["category"] = "YES_NO", ["title"] = "Alarme code entrée", ["mobileDevices"] = {[1] = 822, }, ["data"] = {["actionName"] = "turnOn", ["deviceId"] = 545, }, ["message"] = "Mauvais code entré", ["action"] = "RunAction", ["service"] = "Device", }) Exemple 2: Démarage d'une scène Dans cet exemple on demande à l'utilisateur si il désire lancer une scène lorsque le mauvais code d'entrée est tapé. api.post("/mobile/push", { ["category"] = "RUN_CANCEL", ["title"] = "Alarme code entrée", ["mobileDevices"] = {[1] = 822, }, ["data"] = {["sceneId"] = 133, }, ["message"] = "Mauvais code entré", ["action"] = "Run", ["service"] = "Scene", })
  2. Barelle

    VD UPS

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

    Aide Lua... Utilisation des fonctions.

    Bonjour à tous, Je ne savais pas trop où poster ma demande, donc je choisis le Bistrot. Je ne suis pas programmeur, je bidouille. Et je bug sur l'utilisation des fonctions dans une scène écrite en lua. J'ai donc une scène qui doit avoir le déroulement suivant. Étape 1 - interrogation d'une api via un http.request Étape 2 - on récupère les données transmise à l'étape 1. Étape 3 - on fait une nouvelle interrogation d'une autre api. J'ai donc écris ce que je pense être la colonne vertébrale de mon programme avec les 3 étapes. Et pour chaque étape, j'appelle une fonction que j'ai déclaré dans au début de la scène. (Au dessus de mon code principal). Sauf que j'ai l'impression, en visualisant les fibaro:debug que j'ai mis un peu partout pour voir où en est mon code, que le programme n'attends pas la fin de l'exécution de la fonction pour poursuivre sa route. Je me trompe ?
  4. Ceci n'est pas un tuto, mais plutôt un topic de travail sur l'avancement de mes tests dans l'utilisation de l'API refreshStates, son optimisation, son impact sur les performances de la box, ses limites, etc. Pour rappel, refreshStates permet de récupérer en temps réel tous les événements sur la box. A l'origine, elle a été créée par Fibaro pour les mises à jours de l'interface Web et des applications mobiles. Mais on peut tout à fait l'utiliser dans nos codes LUA, au sein même des QuickApps, puisque ceux-ci ne disposant pas de déclencheurs (triggers) comme les Scènes, cela leur permet ainsi de simuler ces fameux triggers. Actuellement, j'ai un seul QuickApp (GEA) qui utilise cette API, je vais commencer par créer plusieurs QA qui utilisent cette même API et voir comment réagit la box. Le risque probable, c'est une occupation CPU supérieure, pouvant entrainer des ralentissement, voire plantages. Voici un premier bout de code, optimisé "à fond", c'est à dire que pour optimiser au maximum les performances du LUA, je n'utilise que des variables locales, l'objectif étant de limiter autant que possible l'usage des variables (et fonctions) globales, ainsi que le parcours des tables (l'appel d'une variable globale revient à parcourir la table _G), opérations très consommatrices de cycles CPU. De même, le parcours de la table se fait avec for, plus rapide que ipairs(), lui même plus rapide que pairs() Le calcul du nombre d'éléments de la table se fait avant d'entrer dans la boucle for, afin de ne pas refaire le calcul à chaque passage dans la boucle for. Toutes ces optimisations LUA rendent le code moins lisible, donc je les réserve uniquement à cette boucle infinie loop(), car elle va se répéter un grand nombre de fois, à très haute fréquence. Quelques nanosecondes à chaque cycle, ça fini par faire mal mal de secondes à la fin. Le reste du code du QuickApp (non représenté ici) sera développé de façon plus traditionnelle. Pour ces tests, je commence avec un intervalle de 250 ms, soit 1/4 de seconde, ce qui me parait quasiment instantané à l'échelle humaine, et bien suffisant pour mettre à jour l'état d'un QuickApp dans nos scénarios domotiques. Sur GEA, je tourne actuellement à 100ms et ça ne pose à priori aucun problème, je sais que d'autres personnes sur le forum sont descendues à 50 ms. Mais je suppose que d'avoir plusieurs QA avec un intervalle de 50ms ça sera beaucoup plus stressant que 250ms, d'où mon choix de commencer mes tests avec 250 ms. En revanche, en cas d'erreur sur la requête HTTP, j'ai mis un timeout à 5000 ms, soit 5 secondes. Je me dit que si la requête a échoué, c'est peut être parce que la box est saturée, donc attendre plusieurs secondes ne peut que faire du bien. Évidemment j'utilise pcall() à chaque appel de fonction risquée, afin de protéger le code contre tout plantage, et tant pis pour le (léger) risque d'impact sur les performances. Je vais lancer ce bout de code sur plusieurs QA pendant plusieurs heures, et étudier comment se comporte la box (graph CPU) __TAG = "QA_REFRESHSTATES_" .. plugin.mainDeviceId function QuickApp:onInit() self:trace("") self:trace("onInit") self:trace("") end function QuickApp:buttonLoop(event) local lastRefresh = 0 local http = net.HTTPClient() local http_request = http.request local json_decode = json.decode local pcall = pcall local type = type local setTimeout = setTimeout local self_debug = self.debug -- Boucle d'attente d'événements instantanés local function loop() local status, err = pcall(function() local stat, res = http_request(http, "http://127.0.0.1:11111/api/refreshStates?last=" .. lastRefresh, { success = function(res) local status, states = pcall(function() return json_decode(res.data) end) if status then lastRefresh = states.last or 0 local events = states.events local nbEvents = #(events or {}) if nbEvents > 0 then self_debug(self, nbEvents) end for i = 1, nbEvents do local event = events[i] local id = event.data and event.data.id --if id == 123 then --self:debug("Event :", json.encode(event)) --end end else self:error(states or "json.decode() failed") end setTimeout(loop, 250) end, error = function(res) self:error("Error : API refreshStates :", res) setTimeout(loop, 5000) end, }) end) if not status then self:error(err) setTimeout(loop, 5000) end end loop() end PS : pour ce test il faut créer un bouton buttonLoop pour lancer la boucle.
  5. Voici 2 petits scripts LUA pour explorer les objets accessibles dans les QuickApps et les Scènes sur HC3. Quand on développe, il est toujours intéressant de découvrir des variables et fonctions non documentées, ou voir quelles fonctions sont disponibles dans les QuickApps ou dans les Scènes car il y a pas mal de différences. Cela permettra aussi de suivre les ajouts de fonctions par Fibaro au fur et à mesure des nouveaux firmwares. Les résultats donnés dans ce post sont été obtenus avec le firmware 5.031.33 QuickApps Créer un QA avec un seul bouton pour lancer l'exécution du code : function QuickApp:browse(racine, tableau) local variables, functions, objects = {}, {}, {} for k, v in pairs(tableau) do if type(v) == "table" then if v ~= _G then local variables2, functions2, objects2 = self:browse(racine .. k .. ".", v) for i = 1, #variables2 do variables[#variables+1] = variables2[i] end for i = 1, #functions2 do functions[#functions+1] = functions2[i] end for i = 1, #objects2 do objects[#objects+1] = objects2[i] end end elseif type(v) == "function" then functions[#functions+1] = racine .. k .. '()' elseif type(v) == "string" then variables[#variables+1] = racine .. k .. ' = "' .. v .. '"' elseif type(v) == "number" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) elseif type(v) == "integer" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) elseif type(v) == "boolean" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) else objects[#objects+1] = racine .. k .. " => " .. type(v) end end table.sort(variables) table.sort(functions) table.sort(objects) return variables, functions, objects end function QuickApp:onButtonClic(event) self:trace("") local variables, functions, objects = self:browse("", _G) self:trace("Variables :") for _, v in ipairs(variables) do self:debug(v) end self:trace("Fonctions :") for _, v in ipairs(functions) do self:debug(v) end self:trace("Objets :") for _, v in ipairs(objects) do self:debug(v) end self:debug("Terminé") end function QuickApp:onInit() end Résultat : Variables : _VERSION = "Lua 5.3" __TAG = "QuickApp152" json._COPYRIGHT = "Copyright (c) 2007-2017 Thomas Harning Jr. " json._DESCRIPTION = "LuaJSON : customizable JSON decoder/encoder" json._VERSION = "1.3.4" json.decode.simple.array.allowEmptyElement = false json.decode.simple.array.trailingComma = true json.decode.simple.calls.allowEmptyElement = false json.decode.simple.calls.allowUndefined = false json.decode.simple.calls.trailingComma = true json.decode.simple.number.exp = true json.decode.simple.number.frac = true json.decode.simple.number.hex = false json.decode.simple.number.inf = true json.decode.simple.number.nan = true json.decode.simple.object.allowEmptyElement = false json.decode.simple.object.identifier = true json.decode.simple.object.number = true json.decode.simple.object.trailingComma = true json.decode.simple.others.allowUndefined = true json.decode.simple.others.null = false json.decode.simple.others.undefined = false json.decode.simple.strings.additionalEscapes = false json.decode.simple.strings.badChars = "" json.decode.simple.strings.strict_quotes = false json.decode.strict.array.allowEmptyElement = false json.decode.strict.array.trailingComma = false json.decode.strict.calls.allowEmptyElement = false json.decode.strict.calls.allowUndefined = false json.decode.strict.calls.trailingComma = true json.decode.strict.initialObject = true json.decode.strict.nothrow = false json.decode.strict.number.exp = true json.decode.strict.number.frac = true json.decode.strict.number.hex = false json.decode.strict.number.inf = false json.decode.strict.number.nan = false json.decode.strict.object.allowEmptyElement = false json.decode.strict.object.identifier = false json.decode.strict.object.number = false json.decode.strict.object.trailingComma = false json.decode.strict.others.allowUndefined = false json.decode.strict.strings.additionalEscapes = false json.decode.strict.strings.badChars = " " json.decode.strict.strings.strict_quotes = true json.decode.strict.unicodeWhitespace = true json.decode.util.DecimalLpegVersion = 1.0 json.encode.default.number.inf = true json.encode.default.number.nan = true json.encode.default.others.allowUndefined = true json.encode.default.strings.encodeSet = "\"/%z-" json.encode.default.strings.xEncode = false json.encode.strict.initialObject = true json.encode.strict.number.inf = false json.encode.strict.number.nan = false json.encode.strict.others.allowUndefined = false json.encode.strict.strings.encodeSet = "\"/%z-" json.encode.strict.strings.xEncode = false logger.DEBUG = 1 logger.ERROR = 4 logger.FATAL = 5 logger.INFO = 2 logger.TRACE = 0 logger.WARNING = 3 math.huge = inf math.maxinteger = 9223372036854775807 math.mininteger = -9223372036854775808 math.pi = 3.1415926535898 plugin.mainDeviceId = 152 utf8.charpattern = "[-�-�][�-�]*" Fonctions : __assert_type() __fibaroSleep() __fibaroUseAsyncHandler() __fibaro_add_debug_message() __fibaro_get_device() __fibaro_get_device_property() __fibaro_get_devices() __fibaro_get_global_variable() __fibaro_get_room() __fibaro_get_scene() __print() __ternary() api.delete() api.get() api.post() api.put() assert() bit32.arshift() bit32.band() bit32.bnot() bit32.bor() bit32.btest() bit32.bxor() bit32.extract() bit32.lrotate() bit32.lshift() bit32.replace() bit32.rrotate() bit32.rshift() class() clearInterval() clearTimeout() collectgarbage() configure() error() fibaro.__houseAlarm() fibaro.alarm() fibaro.alert() fibaro.call() fibaro.callGroupAction() fibaro.clearTimeout() fibaro.debug() fibaro.emitCustomEvent() fibaro.error() fibaro.get() fibaro.getDevicesID() fibaro.getGlobalVariable() fibaro.getIds() fibaro.getName() fibaro.getRoomID() fibaro.getRoomName() fibaro.getRoomNameByDeviceID() fibaro.getSectionID() fibaro.getType() fibaro.getValue() fibaro.profile() fibaro.scene() fibaro.setGlobalVariable() fibaro.setTimeout() fibaro.sleep() fibaro.trace() fibaro.useAsyncHandler() fibaro.wakeUpDeadDevice() fibaro.warning() getHierarchy() ipairs() json.array() json.decode.decode() json.decode.getDecoder() json.decode.simple.object.setObjectKey() json.decode.simple.strings.decodeUnicode() json.decode.strict.object.setObjectKey() json.decode.strict.others.null() json.decode.strict.others.undefined() json.decode.strict.strings.decodeUnicode() json.decode.util.denied() json.decode.util.get_invalid_character_info() json.decode.util.setObjectKeyForceNumber() json.decode.util.unexpected() json.encode.default.array.isArray() json.encode.default.others.null() json.encode.default.others.undefined() json.encode.encode() json.encode.getEncoder() json.encode.strict.array.isArray() json.encode.strict.others.null() json.encode.strict.others.undefined() json.null() json.util.InitArray() json.util.IsArray() json.util.buildCall() json.util.clone() json.util.decodeCall() json.util.doOptionMerge() json.util.isCall() json.util.merge() json.util.null() json.util.printValue() json.util.undefined() logger.debug() logger.error() logger.fatal() logger.getLevel() logger.info() logger.log() logger.setLevel() logger.trace() logger.warning() math.abs() math.acos() math.asin() math.atan() math.atan2() math.ceil() math.cos() math.cosh() math.deg() math.exp() math.floor() math.fmod() math.frexp() math.ldexp() math.log() math.log10() math.max() math.min() math.modf() math.pow() math.rad() math.random() math.randomseed() math.sin() math.sinh() math.sqrt() math.tan() math.tanh() math.tointeger() math.type() math.ult() next() onAction() onUIEvent() os.clock() os.date() os.difftime() os.exit() os.time() pairs() pcall() plugin.createChildDevice() plugin.deleteDevice() plugin.getChildDevices() plugin.getDevice() plugin.getProperty() plugin.restart() print() property() rawlen() select() setInterval() setTimeout() string.byte() string.char() string.dump() string.find() string.format() string.gmatch() string.gsub() string.len() string.lower() string.match() string.pack() string.packsize() string.rep() string.reverse() string.split() string.starts() string.sub() string.unpack() string.upper() super() table.concat() table.insert() table.move() table.pack() table.remove() table.sort() table.unpack() tonumber() tostring() type() unpack() utf8.char() utf8.codepoint() utf8.codes() utf8.len() utf8.offset() xpcall() Objets : Device => userdata Hierarchy => userdata QuickApp => userdata QuickAppBase => userdata QuickAppChild => userdata core.EventTarget => userdata json.decode.simple.strings.escapeCheck => userdata json.decode.strict.strings.escapeCheck => userdata json.decode.util.ascii_ignored => userdata json.decode.util.ascii_space => userdata json.decode.util.comment => userdata json.decode.util.comments.c => userdata json.decode.util.comments.cpp => userdata json.decode.util.hex => userdata json.decode.util.hexpair => userdata json.decode.util.identifier => userdata json.decode.util.unicode_ignored => userdata json.decode.util.unicode_space => userdata mqtt.Client => userdata mqtt.ConnectReturnCode => userdata mqtt.QoS => userdata net.HTTPClient => userdata net.TCPSocket => userdata quickApp => userdata Scènes Créer une scène LUA en exécution manuelle avec ce code : local function browse(racine, tableau) local variables, functions, objects = {}, {}, {} for k, v in pairs(tableau) do if type(v) == "table" then if v ~= _G and v ~= _ENV and v ~= __index and k ~= "__index" then local variables2, functions2, objects2 = browse(racine .. k .. ".", v) for i = 1, #variables2 do variables[#variables+1] = variables2[i] end for i = 1, #functions2 do functions[#functions+1] = functions2[i] end for i = 1, #objects2 do objects[#objects+1] = objects2[i] end end elseif type(v) == "function" then functions[#functions+1] = racine .. k .. '()' elseif type(v) == "string" then variables[#variables+1] = racine .. k .. ' = "' .. v .. '"' elseif type(v) == "number" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) elseif type(v) == "integer" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) elseif type(v) == "boolean" then variables[#variables+1] = racine .. k .. ' = ' .. tostring(v) else objects[#objects+1] = racine .. k .. " => " .. type(v) end end table.sort(variables) table.sort(functions) table.sort(objects) return variables, functions, objects end fibaro.trace(tag, "") local variables, functions, objects = browse("", _ENV) fibaro.trace(tag, "Variables :") for _, v in ipairs(variables) do fibaro.debug(tag, v) end fibaro.trace(tag, "Fonctions :") for _, v in ipairs(functions) do fibaro.debug(tag, v) end fibaro.trace(tag, "Objets :") for _, v in ipairs(objects) do fibaro.debug(tag, v) end fibaro.debug(tag, "Terminé") Résultat : Variables : fibaro.version = "1.0.0" json._version = "0.1.0" math.huge = inf math.maxinteger = 9223372036854775807 math.mininteger = -9223372036854775808 math.pi = 3.1415926535898 sceneId = 10 sourceTrigger.id = 2 sourceTrigger.property = "execute" sourceTrigger.type = "user" tag = "Scene10" Fonctions : api.delete() api.get() api.post() api.put() assert() error() fibaro.alarm() fibaro.alert() fibaro.call() fibaro.callGroupAction() fibaro.debug() fibaro.emitCustomEvent() fibaro.error() fibaro.get() fibaro.getAllDeviceIds() fibaro.getDevicesID() fibaro.getGlobalVariable() fibaro.getIds() fibaro.getName() fibaro.getRoomID() fibaro.getRoomName() fibaro.getRoomNameByDeviceID() fibaro.getSectionID() fibaro.getType() fibaro.getValue() fibaro.homeCenter.climate.setClimateZoneToManualMode() fibaro.homeCenter.climate.setClimateZoneToScheduleMode() fibaro.homeCenter.climate.setClimateZoneToVacationMode() fibaro.homeCenter.notificationService.publish() fibaro.homeCenter.notificationService.remove() fibaro.homeCenter.notificationService.update() fibaro.homeCenter.popupService.publish() fibaro.homeCenter.systemService.reboot() fibaro.homeCenter.systemService.suspend() fibaro.profile() fibaro.scene() fibaro.setGlobalVariable() fibaro.setTimeout() fibaro.sleep() fibaro.trace() fibaro.wakeUpDeadDevice() fibaro.warning() ipairs() json.decode() json.encode() math.abs() math.acos() math.asin() math.atan() math.atan2() math.ceil() math.cos() math.cosh() math.deg() math.exp() math.floor() math.fmod() math.frexp() math.ldexp() math.log() math.log10() math.max() math.min() math.modf() math.pow() math.rad() math.random() math.randomseed() math.sin() math.sinh() math.sqrt() math.tan() math.tanh() math.tointeger() math.type() math.ult() net.HTTPClient.new() net.HTTPClient.request() next() os.date() os.time() pairs() pcall() print() select() string.byte() string.char() string.dump() string.find() string.format() string.gmatch() string.gsub() string.len() string.lower() string.match() string.pack() string.packsize() string.rep() string.reverse() string.sub() string.unpack() string.upper() table.concat() table.insert() table.move() table.pack() table.remove() table.sort() table.unpack() tonumber() tostring() type()
  6. Felig

    QuickApp pour les Nuls

    Pour ceux qui connaissent HC2 mais débutent en HC3, voici des réponses aux principales questions que je me suis posées ces derniers jours. Rien de nouveau, tout est sur le forum (et en plusieurs exemplaires !) mais l'idée est de faire un post avec les principes de base et questions fréquentes (actualisé si besoin en fonction de vos commentaires/corrections), pour les débutants en HC3 qui comme moi sont très mauvais avec les moteurs de recherche. Sources et liens essentiels: ils sont indiqués par @Lazer ici. Un grand merci à lui, beaucoup de mes apprentissages viennent de ses posts. Qu'est-ce qu'un QuickApp (QA) ? Un QA est 3 composants en 1 : Un script LUA, qui peut être organisé en plusieurs fichiers: par exemple un fichier pour votre programme principal ("main"), un fichier pour une librairie de tools, un fichier pour la config utilisateur, etc. Pour utiliser une fonction du fichier tools, il suffit de l'appeler par son nom dans l'onglet principal. Pour créer un nouveau fichier, cliquer sur l’icône Files dans la marge à gauche de l'interface UI. Un module virtuel (device). Contrairement aux VD de HC2, le module virtuel d'un QA simule un module physique (interrupteur, détecteur, sonde, etc.). C'est pour ça que chaque fois qu'on crée un QA il faut choisir le type de device associé. En fonction du type, vous aurez des propriétés ("lastBreached" pour un détecteur par exemple), des icônes, et une interface utilisateur spécifiques équivalentes à ce que vous auriez pour un QA physique du même type. L'idée est que ce module virtuel soit piloté par la HC3 de la même manière que s’il était réel, via des appels fibaro.get(), fibaro.getValue(), fibaro.call() et même via l’API. Le grand avantage est que vous pouvez personnaliser et modifier son « micro-programme » et son interface (UI), ce qui n'est pas possible pour un module réel. La liste des types disponibles et propriétés associées est ici (fichier excel à la fin du post). C'est aussi si besoin une interface (UI) avec des labels, boutons, sliders, comme un VD de HC2. Attention, l'interface par défaut dépend du type de device que vous sélectionnez à la création du QA (cf. ci-dessus). Chaque composant est optionnel. Comme illustré ici il est possible d'avoir des modules QA qui fonctionnent sans une ligne de code (pilotés par des calls externes). Et inversement, si vous n'avez pas besoin de module virtuel, vous pouvez sélectionner l'option "Appareil désactivé" ("Device disabled") dans l'onglet "Avancé" du QA : le QA ne pourra plus être appelé par des calls fibaro, mais le programme LUA fonctionnera normalement et l'interface UI aussi (par contre j'ai l'impression que ça fait disparaitre le QA de l'interface mobile, donc pas forcément une bonne idée...). Comment fonctionnent les variables persistantes dans un QA ? Dans HC2, si on veut une variable persistante, on a le choix entre un label de VD ou une variable globale. Les variables globales existent toujours dans la HC3, elles sont gérées par les fonctions fibaro.getGlobalVariable(var) et fibaro.setGlobalVariable(var, value). Par contre les labels de QA ne sont plus persistants (réinitialisés à chaque démarrage du QA), et leur contenu n'est pas facile à lire (pas de fonction fibaro, il faut passer par le JSON du QA). Mais heureusement ils sont remplacés par les "variables QA" (« quickVars ») : des variables persistantes, mais internes au QA. Ces variables sont gérées par les fonctions QuickApp:getVariable(var) et QuickApp:setVariable(var, value). A noter : Si la "quickVar" n'existe pas, QuickApp:getVariable() renverra une valeur "" et non nil. Il y aura juste un warning dans le log du QA si la variable n'existe pas. Si vous utilisez QuickApp:setVariable() sur une quickVar qui n'existe pas, elle sera créée. Les quickVars peuvent aussi être créées, modifiées ou supprimées dans les paramètres du QA (onglet Variables). MAIS : toute valeur saisie manuellement dans l’interface Web sera convertie en format string (« 99 » au lieu de 99). Pour utiliser un autre format (numérique ou table), il faut utiliser QuickApp:setVariable(). Il est possible de récupérer le contenu des quickVars d'autres QA par des fonctions détournées (mais ce n'était pas l'intention des développeurs). Les variables globales HC3 peuvent être gérées dans l'onglet Variables du menu Réglages/Général (basique, mais j'ai mis du temps à le trouver!). Comment fonctionnent les fonctions dans un QA ? Compte tenu de ce qui précède, ça ne devrait pas vous étonner qu’on ait deux types de fonction : les fonctions normales de n’importe quel code LUA (function test(x) return x+x end) et les fonctions QuickApp qui sont ajoutées au code du module virtuel (son « micro-programme » pour reprendre mon image initiale). L’intérêt principal des fonctions QuickApp est qu’elles sont appelables par d’autres QA. L’autre intérêt est que chaque QA vient avec des fonctions déjà existantes qui sont bien utiles (ex : QuickApp:debug(), QuickApp:getVariable(), etc.). La fonction de gestion de l’interface UI notamment est une fonction QuickApp. Le QA simule une logique de langage orienté objet. Pour faire un parallèle avec Python (le seul langage orienté objet que je pratique un peu), QuickApp est une classe qui contient des fonctions (ou méthodes) mais aussi des variables (QuickApp.id est l'id du QA par exemple). Au sein d'une fonction QuickApp les autres fonctions et variables du QA peuvent être appelées par self:fonction() ou self.variable. L’appel d'une fonction d’un autre QA se fait via fibaro.call(id, "maFonction", arg1, arg2, etc.). L'inconvénient de cette méthode est qu'il n'y a pas de retour (pas de confirmation de succès, ni possibilité de renvoyer une variable au QA d'origine). Là aussi, il est possible de régler le problème par des contournements, comme expliqué ici. Comment est structuré le code LUA d’un QA ? La structure normale du code LUA d’un QuickApp est comme suit : Le code est exécuté une première fois de haut en bas. C'est l'occasion de déclarer les variables et fonctions. Ensuite, le QA lance la fonction QuickApp:onInit() si elle existe. C'est dans cette fonction que votre code doit commencer normalement. Voici un exemple (fonctionne avec un QA de type "multilevel sensor", qui accepte des valeurs numériques pour sa propriété "value"): function QuickApp:turnOn() -- appelable par fibaro.call(id, "turnOn") self:updateProperty("value", "99") afficheValeur(self) end function QuickApp:turnOff() -- appelable par fibaro.call(id, "turnOff") self:updateProperty("value", "0") afficheValeur(self) end function afficheValeur(self) self:debug("Valeur du module "..self.id.." : "..self.properties.value) end function QuickApp:onInit() self:debug("onInit - Démarrage du module "..self.id) --afficheValeur(self) setTimeout(function() afficheValeur(self) end, 0) end Contrairement au code des VD HC2, le code des QA ne s’exécute qu’une seule fois. Si vous souhaitez une boucle, il faut créer une fonction mainLoop() appelée via une fonction setInterval(). Tout est expliqué ici. Pourquoi on voit souvent l'instruction setTimeout(function() maFonction(self) end, 0) à la fin de la fonction QuickApp:onInit() ? C’est expliqué ici. En résumé, ça permet d’avoir accès à une variable LUA globale « quickApp » qui contient toutes les propriétés et méthodes de la classe QuickApp (instanciation), mais qui ne s’initialise que si la fonction QuickApp:onInit() est terminée. Même si on n'utilise pas cette variable, c'est une bonne habitude de laisser la fonction QuickApp:onInit() se terminer avant de lancer la fonction suivante.
  7. Krikroff

    Les variables dans un Quick App

    L'idée ici est partager nos retours d' expérience sur l'utilisation des variables dans les Quick App. Nous connaissons tous pour la plupart l'existence des variables globales mais le HC3 dans les Quick App apporte une nouvelle notion de variable au niveau du QA. Cela va considérablement simplifier la vie du développeur et du l'utilisateur au quotidien. L'utilisation est très simple et repose sur 2 méthodes: La création ou la mise à jour d'une variable existante : self:setVariable("NOM_DE_LA_VARIABLE", "VALEUR_DE_LA_VARIABLE") > le set se charge de créer la variable si elle n'existe pas, bien joué Fibaro La lecture de la valeur d'une variable : self:getVariable("NOM_DE_LA_VARIABLE") Avouons le c'est difficile de faire plus simple Les variables ainsi ajoutées sont visibles depuis l'onglet "Variables" au niveau du périphérique, comme ceci: Ou bien encore en interrogeant l' API via le SWAGGER intégré au Home Center ...
  8. 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() :
  9. Bonjour, débutant en LUA et scène, j'aimerai retourner la valeur de l'appareil (Aeotec meter Gen5) et pas seulement faire un déclanchement de la scène si > x par exemple ? Merci, HC3, 5.100.22
  10. 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.
  11. Bonjour à tous, Quelques mots au sujet de ma prise en main de la HC3. Tout d'abord, bien suivre la procédure initiale jusqu'au bout, afin de paramétrer le compte, les accès réseaux (éthernet et wifi), etc.. Au sujet de l'interface, quelle fluidité par rapport à la HC2 ! Fini le "flash" blanc entre chaque changement de "page" et les petits points bleus qui tournent en rond. Il va falloir aussi "réapprendre une nouvelle interface, avec une disposition et une philosophie différentes (mais on s'y fait assez vite). Par contre il existe de nouvelles "pages" telles que "Climat", "Jardin", "Profil", qui sont je pense à la fois un apport de nouvelles options et une redistribution des anciennes. Dans le genre, exit l'onglet "Panneaux", et par exemple celui des "Notifications". Apres quelques tests, les notifications (push) s'écrivent directement dans le code (sauf découverte ultérieure). Un peut déroutante également, la zone "Lua", avec à gauche une partie "Déclarations" et à droite une partie "Code". Si je ne me trompe, la partie "Déclaration" doit correspondre à l'ancien entête des scènes ( --[ ... ]-- ) ? Pour taper un peu sur le sempiternel "copper" promotionnel au sujet des LED's de facade, hé ben non ! Y'en a une qui reste(ra) rouge : celle dédiée à "l'installateur Fibaro" - agaçant... J'ai essayé de m'y coller. Hélas non ! Il faut un vrai compte d'installateur. Au sujet cette fois des icônes, toujours en 128 x 128 (j'aurais espéré 512...) Maintenant au taf ! Pas question d'importer le contenu de ma HC2 "brut de forge". Il va falloir un remaniement complet des scènes je pense (sauf si l'importation fait le transcodage). Je m'explique : getGlobalValue() devient getGlobalVariable() ! Dans le même veine : fibaro:getGlobal... devient fibaro.getGlobal... Il doit sûrement y avoir d'autres "subtilités" de ce genre. A toutes fins utiles, le lien vers le manuel Fibaro dédié au Lua "spécial" HC3 : https://manuals.fibaro.com/home-center-3-lua-scenes/ Photo de famille pour finir...
  12. En évaluant le job que j’aurai potentiellement à faire pour changer de box, je me suis mis à inventorier le code LUA utilisé sur ma HC2. Je me suis rendu compte que j’avais dupliqué pas mal de code (fonctions, routines, etc.) et surtout lors de correction de certaines portions de code j’ai oublié de le corriger dans quelques scènes ou ce code était dupliqué… Alors ce week-end, j’ai planché sur une solution me permettant de simplifier mon code et de le centraliser. Donc voici ci-dessous, ce que j'ai effectué. Stratégie création d'une scène que j'ai nommée scGloFuncLib (id:186) et qui est structurée comme suit : VARIABLES/CONSTANTES PERSONNALISABLE PAR L'UTILISATEUR; variables et constantes, modifiable par l'utilisateur, lui permettant d'adapter les valeurs à son environnement; VARIABLES/CONSTANTES INTERNES (à ne pas modifier); variables et constantes, nécessaires au bon fonctionnement de la scène. La valeurs définies ici sont sensées être optimisées et ne devraient pas être modifiées par les utilisateurs => risques d'effets de bord non maîtrisés; LES FONCTIONS INTERNES les fonction internes sont les fonction qui ne sont pas appelée en dehors de la scène, mais qui sont utiles à aux fonctions "exposées"; LES FONCTIONS EXPOSÉES les fonctions exposées, sont les fonction accessibles avec un appel externe depuis une autre scène/VD; MAIN permet d'analyser les arguments et d'appeler les fonctions concernées en vérifiant et en passant les bons paramètres; appel de la scène susmentionnée depuis une autre scène/VD avec le code suivant : fibaro:startScene(186, { "myFunction1", "p1", "p2", "pN" }) Limitations La limitation de ce système pour l'instant et le retour de valeur entre la scène qui appelle la fonction et celle qui l'exécute. N'ayant pour l'instant pas ce besoin, je n'ai rien fait. Mais si cela devait changer, je procéderais certainement de la manière suivante : création d'une variable globale avant l'appel de la fonction; appelle de la fonction via la scène scGloFuncLib en passant le nom de la variable globale créée; récupération de la valeur de la variable globale; destruction de la variable globale. Squelette du code LUA ---- *********************************************************************** ---- VARIABLES/CONSTENTES PERSONNALISABLES PAR L'UTILISATEUR ---- *********************************************************************** ---- Description ---- variables et constantes, modifiable par l'utilisateur, lui ---- permettant d'adapter les valeurs à son système. ---- ------------------------------------------------------------------- ---- myFonction1 ---- ------------------------------------------------------------------- FUNCTION1_DEF_PARAM2 = "123456asdf"; ---- ------------------------------------------------------------------- ---- log_debug ---- ------------------------------------------------------------------- IS_DEBUG_MODE = true; ---- *********************************************************************** ---- VARIABLES/CONSTENTES INTERNES (à ne pas modifier); ---- *********************************************************************** ---- Description ---- variables et constantes, nécessaires au bon fonctionnement de la ---- scène. La valeurs définies ici sont ensées être optimisées et ne ---- devraient pas être modifiées par les utilisateurs => risques ---- d'effets de bord non maîtrisés. ---- ------------------------------------------------------------------- ---- System ---- ------------------------------------------------------------------- MD5_HASH = "cb2b8c02de4f322cd67fd8e7a88d420f"; ---- *********************************************************************** ---- LES FONCTIONS INTERNES ---- *********************************************************************** ---- Description ---- les fonction internes sont les fonction qui ne sont pas appelées ---- en dehors de cette scène, mais qui sont utiles aux fonctions ---- "exposées". ---- ------------------------------------------------------------------- ---- function : log_std ---- ------------------------------------------------------------------- ---- paramètres : ---- str : log a envoyer dans la fenêtre de debug ---- retour : <aucun> ---- ------------------------------------------------------------------- function log_std(str) if IS_DEBUG_MODE then fibaro:debug("<font color='yellow'>"..str.."</font>"); end end ---- *********************************************************************** ---- LES FONCTIONS EXPOSÉES ---- *********************************************************************** ---- Description ---- les fonctions exposées, sont les fonction accessibles avec ---- un appel externe depuis une autre scène/VD. ---- ------------------------------------------------------------------- ---- function : myFunction1 ---- ------------------------------------------------------------------- ---- paramètres ---- _param_no1 : paramètre1 ---- _param_no2 : paramètre2 ---- retour : <aucun> ---- ------------------------------------------------------------------- function myFunction1 (_param_no1, _param_no2) -- * exécution de ma fonction "exposée end ---- *********************************************************************** ---- MAIN ---- *********************************************************************** ---- Description : ---- la boucle principal permet d'analyser les arguments et d'appeler ---- les fonctions concernées en leurs passant les bons paramètres. ---- Arguments : ---- args[1] = <functionName> : nom de la fonction appelée ---- args[n] = <parameters> : parametres des fonctions appelées ---- ------------------------------------------------------------------- -- * première chose à faire vérifier s'il y a des arguments if fibaro:args() == nil then -- * pas d'argmuent alors on sort de la scène return else -- * arguments, alors on les entre dans une table func_args = fibaro:args(); -- * puis on vérifie que le premier argument (nom de la fonction) existe if func_args[1] == nil or func_args[1] == "" then -- * pas de args[1] alors on sort de la scène, car aucune fonction a appeler return -- * si args[1] = myFunction1 alors on traite les paramètres par rapport à cette fonction elseif func_args[1] =="myFunction1" then ---- ------------------------------------------------------------------- ---- calling myFunction1 function ---- ------------------------------------------------------------------- ---- Parameters : ---- args[2] = param_no1 (obligatoire) ---- args[3] = param_no2 ---- ------------------------------------------------------------------- local param_no1,param_no2 -- * vérificatio du premier paramètre args[2] qui est obligatoire if func_args[2] == nil or func_args[2] == "" then -- * le paramètre est obligatoire, alors si pas renseigné on sort de la scène return else -- * on attribue args[2] à la variable param_no1 param_no1 = func_args[2]; end -- * vérificatio du deuxième paramètre args[2] qui est facultatif if func_args[3] == nil or func_args[3] == "" then -- * le paramètre est facultatif, possibilité d'attribuer une valeur par défaut si vide ou null param_no2 = FUNCTION1_DEF_PARAM2; else -- * on attribue args[2] à la variable param_no2 param_no2 = func_args[3]; end myFunction1 (param_no1,param_no2); return else -- * si args[1] ne correspond à aucune des fonctions exposées (func_args[1] =="FunctionName") , alors on sort de la scène. return end -- fin de l'execution de la scène. end
  13. Lazer

    Interrompre le code LUA d'un QuickApp

    Savez vous s'il est possible d'interrompre brutalement le déroulement du code LUA d'un QuickApp ? Sur HC2 on avait la commande fibaro:abort() qui faisait cela, je me demande s'il existe l'équivalent sur HC3 ? J'ai bien comme idée de provoquer un crash du QuickApp en appelant une fonction non définie, mais ce n'est pas vraiment propre... Note : l'utilisation de l'instruction return n'est pas adaptée à mon cas de figure car il y a plein de fonctions imbriquées les unes dans les autres
  14. idomotique

    Les tableaux en LUA

    Bonjour, Après m'être cassé la tête pendant plusieurs jours pour arriver à formater des tableaux sur HC3 dans la zone de debug voici la solution: 1. Création du Tableau local TabToPrint = {} -- Création du tableau vide 2. Création de la ligne de titre Je ne vais pas vous faire un cours HTML mais sachez que le secret sur la HC3 (ne le dites à personne hein ) c'est que le HTML5 n'est pas supporté. Il faut donc utiliser les balises HTML4. Donc nous commençons par créer une ligne de titre avec la balise "<table>" qui ouvre le tableau, la balise "<tr>" qui crée une nouvelle ligne et la balise "<th>" qui ouvre un nouvel élément titre. Bien entendu sans oublier de refermer chaque balise sauf la balise "<table>" que l'on fermera à la fin du tableau. Cette ligne est affectée à la première ligne du tableau avec "TabToPrint[1] = " TabToPrint[1] = "<table><tr><th>Description</th><th>Valeur</th></tr>"; on voit dans cet exemple que j'ai crée 2 colonnes "Description" et "Valeur" 3.Création des éléments du tableau Nous utilisons basiquement la même commande que pour la ligne de titre au détail prêt que nous remplaçons la balise "<th>" par la balise "<td>" pour un élément de tableau. Pour être honnête cela ne change pas grand chose mais c'est plus propre et cela vous aidera à vous y retrouver dans votre code. TabToPrint[#TabToPrint+1] = "<tr><td>Current firmware version</td><td>" data.version "</td></tr>"; Vous remarquerez le début de la ligne "TabToPrint[#TabToPrint+1]" cela permet de récupérer la dernière ligne du tableau et de rajouter notre ligne à sa suite. Vous pouvez aussi utiliser "TabToPrint[2]" et incrémenter manuellement mais vous avez de bonnes chances de faire une erreur et d'écraser des lignes. Il est également possible d'intégrer des variables comme éléments du tableau comme dans cet exemple le "data.version"qui est une variable locale. 4. Impression du tableau Lorsque vous avez crée tous vos éléments vous pouvez imprimer le tableau dans l'interface de debug avec la commande suivante. fibaro.trace("Scene145", table.concat(TabToPrint) .. "</table>") l'élément "table.concat() " permet de concaténer tous les éléments de votre tableau et comme expliqué au début il faut également fermer votre tableau avec la balise "</table>" voila vous obtenez un premier tableau Bon c'est pas bien joli pour le moment alors mettons y un peu les formes.... 5. formater le tableau Pour formater notre tableau nous allons utiliser des attributs tels que "bgcolor = "green"". Oui mais alors la c'est un peu délicat vu que l'on doit utiliser des guillemets pour notre attribut ce qui aura pour conséquence de fermer notre string dans la commande et lua va considérer "green" comme une variable ce qui n'est pas notre but. Pour contourner cela un 2ème petit secret: en LUA il es possible d'utiliser le caractère "\" pour que le caractère qui suit immédiatement ne soit pas interprété par lua. En clair avec la commande "bgcolor = \"green\"" les guillemets qui entourent "green" seront considérés par le compilateur comme du texte. Voici donc quelques exemples de formatage du tableau Appliquer une couleur de fond attribut: bgcolor = \"green\" appliquer sur: table, ligne ou éléments du tableau TabToPrint[1] = "<table bgcolor = \"green\"><tr><th>Description</th><th>Valeur</th></tr>"; résultat: Ajout de bordures attribut: border = \"1\" appliquer sur: table TabToPrint[1] = "<table bgcolor = \"green\" border = \"1\"><tr><th>Description</th><th>Valeur</th></tr>"; résultat: Changer la couleur d'un texte: attribut: <font color=red> appliquer sur: texte TabToPrint[1] = "<table bgcolor = \"green\" border = \"1\"><tr><th><font color=red>Description</th><th><font color=red>Valeur</th></tr>"; résultat: vous trouverez d'autres possiblités de formattage avec les balises html ici 5. Exemple Voici un exemple de formatage d'un éléments de réponse d'une requête API sur un interrupteur Dingz: -- configuration des tableaux local styleElement= "<font color=black size=\"3\">" local styleTitre = "<font color= \"#E4022E\" size=\"5\">" local styleTableau ="bgcolor = \"#a6ff19\" border = \"1\" cellpadding = \"5\" width = \"1000\"" -- Ligne de titre TabToPrint[1] = "<table "..styleTableau.."><tr><th>".. styleTitre .. "Description</th><th>".. styleTitre .. "Valeur</th></tr>"; -- Remplissage du tableau TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Current firmware version</td><td>"..styleElement.. tostring(data.version) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td"..styleElement.. ">MAC address, without any delimiters</td><td>"..styleElement.. tostring(data.mac) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Device type it always have value 108</td><td>"..styleElement.. tostring(data.type) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "SSID of the currently connected network</td><td>"..styleElement.. tostring(data.ssid) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Current ip address</td><td>"..styleElement.. tostring(data.ip) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Mask of the current network</td><td>".. styleElement .. tostring(data.mask) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Gateway of the current network</td><td>".. styleElement .. tostring(data.gateway) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "DNS of the curent network</td><td>".. styleElement .. tostring(data.dns) .."</td></tr>"; TabToPrint[#TabToPrint+1] = "<tr><td>"..styleElement.. "Wether or not the ip address is static</td><td>"..styleElement.. tostring(data.static) .."</td></tr>"; --impression du tableau fibaro.trace("Scene145", table.concat(TabToPrint) .. "</table>") Vous remarquerez que pour simplifier les choses j'ai crée des variables "style..." avec les attributs. cela permet de rassembler le tout à un endroit et de ne pas avoir a grailler dans vos tableau. résultat: Voila il je ne suis absolument pas un pro du HTML donc si vous avez des remarques ou des conseil pour faire mieux je suis volontiers preneur mais avec ces explications vous avez une base pour faire quelques tableaux. PS: interdiction formelle de se moquer de mon sens artistique
  15. jjacques68

    getSourceTrigger

    Hello tout le mode ! On a visiblement plus le getSourceTrigger dans la HC3 du coup pour une scène qui a comme trigger ce genre de chose : { operator = "any", conditions = { { type = "device", id = 10, property = "value", operator = "==", value = true, isTrigger = true }, { type = "device", id = 12, property = "value", operator = "==", value = true, isTrigger = true } } } et qu’on cherche à savoir qui à déclenché la scène ? comment fait-on ? merciiiii !
  16. jjacques68

    Conditions/Triggers

    Encore moi désolé j'ai tendance à bombarder le forum de questions, mais je vous promets que je cherche des réponses avant de poster Alors on en avait un peu discuté avec @Lazer je crois, mais je me rends compte que les Trigger dans les scènes semblent être plus compliqués... Je m'explique : Je veux qu'une scène soit triggée lorsque qu'un Wall Plug (pour cette exemple) change d'état. Et bien je suis obligé de mettre 2 lignes de conditions, une pour tester le "True" et pour le "False". { operator = "any", conditions = { {type = "device", id = 34, property = "value", operator = "==", value = true, isTrigger = true}, {type = "device", id = 34, property = "value", operator = "==", value = false, isTrigger = true} } } Je pensais qu'il était possible, par exemple, d'en avoir qu'une : { operator = "any", conditions = { {type = "device", id = 34, property = "value", operator = "!=", value = 2, isTrigger = true}, } } Mais visiblement, il n'accepte (pour ce type de module) que le "True" et "False" comme "value". Alors imaginons maintenant que cette scène doit être triggée par tout tout tout plein de device ! La liste des conditions va exploser, minimum le double que ce qu'on faisait sur la HC2 !! c'est un peu bof comme méthode non ? où je me trompe complètement !
  17. Krikroff

    LUA dans les scènes sur HC3

    La documentation officielle est consultable sur https://manuals.fibaro.com/home-center-3-lua-scenes/
  18. Voici un Scène qui va vous permettre de savoir si on est le jour ou la nuit et d'avoir un décalage en minute par rapport ou jour ou a la nuit IL va nous falloir pour cette scène 2 variables globales et 1 variable globale prédéfinie Jour_Nuit (Variable prédéfinie avec comme valeur Jour ou Nuit. elle aura 2 déclenchements) SoleilLever (cette variable recevra les valeurs de la table TLever elle aura donc autant de déclenchement que de valeur dans la table TLever) SoleilCoucher (Cette variable recevra les valeurs de la table TCoucher, elle aura donc autant de déclenchement que de valeur dans la table TCoucher) Ces variables seront créées automatiquement si vous êtes en V4. Vous pouvez donnez un autre nom a chaque variable globales que les valeurs par défaut. -- Nom des Variables Globales local VGJourNuit = "Jour_Nuit" local VGLeverSoleil = "SoleilLever" local VGCoucherSoleil = "SoleilCoucher" -- Minutes de décalages par rapport au lever du soleil local TLever = {-60, -15, 30, 60, 50, 124} -- Minutes de décalages par rapport au Coucher du soleil local TCoucher = {-5, 30, 0, -30} -- Id du téléphone local IdTel = 181 Pour notre ami JoJo ainsi qu'a tout ceux qui sont en V3.60 il faudra crées les variables manuellement et désactivé ces trois lignes VerifVG(VGJourNuit, "Jour", {"Jour", "Nuit"}) VerifVG(VGLeverSoleil, 0) VerifVG(VGCoucherSoleil, 0) ----------------------------- Il faut renseigner IdTel avec l'id de votre téléphone cela va servir a vous envoyez une notification lorsque la box démarre ou lorsqu il y a modification de la scène. Une notification est aussi possible si il y a un probléme de variable globale. Le programme est optimisez pour que le sleep passe automatiquement de 1 mn à 30 mn en fonction des valeurs des tables coucher et lever Exemple d'utilisation : Scène bloc : Scène LUA je veux un déclenchement de scène (Il n'y a aucun ordre a respecter) 45 minutes avant le lever = -45 15 minutes avant le lever = -15 23 minutes apres le lever = 20 1h20 minutes apres le lever = 80 0 minutes = Jour dans la tables TLever il est donc inutile de mettre 0, il sera ajouter automatiquement a la table Je renseigne donc ma table TLever comme ceci local TLever = {-45, 20, 80, -15} Je fais de même avec la table TCoucher local TCoucher = {-5, 30, -30} Récupération des triggers dans une scène Utilisation de la variables globales Jour_Nuit comme trigger --[[ %% globals Jour_Nuit --]] local JourNuit = fibaro:getGlobalValue("Jour_Nuit") if JourNuit == "Jour" then fibaro:debug("Il fait "..JourNuit) end if JourNuit == "Nuit" then fibaro:debug("Il fait "..JourNuit) end Utilisation de ou des variables globales SoleilLever et SoleilCoucher comme trigger --[[ %% globals SoleilLever SoleilCoucher --]] local trigger = fibaro:getSourceTrigger() if (trigger['type'] == 'global') then LeverCoucher = trigger['name'] valeur = tonumber(fibaro:getGlobalValue(LeverCoucher)) print(nom, valeur) end -- le code dans ce test sera déclencher 15 mn aprés le coucher if LeverCoucher == "SoleilCoucher" and valeur == 15 then fibaro:call(7, "close") --Fermeture volet 15 mn après le coucher end -- le code dans ce test sera déclancher 30 mn avant le coucher if nom == "SoleilLever" and valeur == -30 then fibaro:call(7, "close") --Fermeture volet 30 mn avant le lever du soleil end Merci a STEVEN pour m'avoir aider a optimisez ce code Voici le code a copier dans une scène Version 3.00b --[[ %% autostart --]] -- Nom des Variables Globales local VGJourNuit = "Jour_Nuit" local VGLeverSoleil = "SoleilLever" local VGCoucherSoleil = "SoleilCoucher" -- Minutes de décalages par rapport au lever du soleil local TLever = {-60, -15, 30, 60, 50, 124} -- Minutes de décalages par rapport au Coucher du soleil local TCoucher = {-5, 30, 0, -30} -- Id du téléphone local IdTel = 181 --************ Ne rien modifier en dessous de cette ligne ************ ---------------------------------------------------------------------- -- Envoi d'un Push pour avertir que le box à démarrer ou redémarrer -- ---------------------------------------------------------------------- function EnvoiPush(Message) fibaro:debug(Message) fibaro:call(IdTel, "sendPush", Message) end -- ----------------------------------------------------------------- -- Vérification Variable Globale et création si besoin -- -- ----------------------------------------------------------------- function VerifVG(nom, valeur, choix) if (fibaro:getGlobalValue(nom) == nil) then local enum = 0 if (type(choix) ~= "nil") then enum = 1 end api.post("/globalVariables", {name=nom, isEnum=enum}) if enum == 1 then local variable = {} variable.value = tostring(valeur) variable.isEnum = false if (type(choix) ~= "nil") then variable.isEnum = true variable.enumValues = choix end api.put("/globalVariables/" .. nom, variable) end end end ---------------------------------------------------------------------- -- Mise a jour d'une variable global -- ---------------------------------------------------------------------- function UpdateVG(NomVG, Valeurs) if (fibaro:getGlobalValue(NomVG) == nil) then fibaro:debug("il faut cree la variable "..NomVG) EnvoiPush(string.format("La variable Globale %s n'existe pas ou a ete supprimer", NomVG)) fibaro:abort() -- fin du programme end fibaro:debug("Mise a jour de la Variable Globale : "..NomVG.." = "..Valeurs) fibaro:setGlobal(NomVG, Valeurs); end ---------------------------------------------------------------------- -- Vérification de l'heure et mise à jour -- -- de la variable si nécessaire -- ---------------------------------------------------------------------- function UpdateJourNuit(NomVG, heure) local valeurs = "Nuit" -- test si on est le jour ou la nuit if (heure >= leverSoleil) and (heure < coucherSoleil) then valeurs = "Jour" end fibaro:debug(string.format("Lever Soleil : %s - Coucher Soleil : %s", leverSoleil, coucherSoleil)) UpdateVG(NomVG, valeurs) -- mise a jour de la VG Jour_Nuit end ---------------------------------------------------------------------- -- Compare les tables Lever et coucher du soleil -- -- avec sunrisehour et sunsethour -- ---------------------------------------------------------------------- function LeverCoucher(NomVG, TableNom, SunRiseSet, JourNuit) for index, v in ipairs(TableNom) do if (os.date("%H:%M", os.time()+v*-60)) == SunRiseSet then UpdateVG(NomVG, v) if v == 0 then fibaro:debug("il fait : "..JourNuit) UpdateVG(VGJourNuit, JourNuit) end end end end ---------------------------------------------------------------------- -- Conversion Date format texte en format Date -- ---------------------------------------------------------------------- function ConvertionDate(NomDate) -- on extrait l'heure et minute (%d+) est un digit local heure, minute = string.match(NomDate, "(%d+):(%d+)") -- On récupère l'heure et date actuelle sous forme de tableau local TableDate = os.date("*t") -- On modifie l'heure et les minutes TableDate.hour = heure TableDate.min = minute -- Nous pouvons maintenant exploiter "MonHeure" comme une vrai date local MonHeure = os.time(TableDate) return (MonHeure) end ---------------------------------------------------------------------------- -- Calcul la valeur du Sleep en fonction des Max et Mini -- -- des Tables Lever et Coucher -- ---------------------------------------------------------------------------- function calculPause(j, heure, minilever, maxilever, minicoucher, maxicoucher) fibaro:debug("Heure Actuelle : "..heure) -- mini et max lever local heurelever = ConvertionDate(leverSoleil) local heureleverMini = (os.date("%X", heurelever+(minilever*60))) local heureleverMaxi = (os.date("%X", heurelever+(maxilever*60))) fibaro:debug("heure Lever Soleil Mini : "..heureleverMini.." - Maxi : "..heureleverMaxi) -- mini et max coucher local heurecoucher = ConvertionDate(coucherSoleil) local heurecoucherMini = (os.date("%X", heurecoucher+(minicoucher*60))) local heurecoucherMaxi = (os.date("%X", heurecoucher+(maxicoucher*60))) fibaro:debug("heure Coucher Soleil Mini : "..heurecoucherMini.." - Maxi : "..heurecoucherMaxi) if heure >= heureleverMini and heure < heureleverMaxi or heure >= heurecoucherMini and heure < heurecoucherMaxi then j=1 end return (j) end -- =================================================================== -- == Nous avons fini la préparation de notre code == -- == Nous pouvons Exécuter le programme == -- == Script réaliser par MPRINFO Version 3.00B == -- == Grand Merci à STEVEN pour son aide == -- =================================================================== ---------------------------------------------------------------------- -- Envoi d'un Push pour donner la date et l'heure de démarrage -- ---------------------------------------------------------------------- EnvoiPush(string.format("La box a démarré le %s a %s", os.date("%d/%m/%Y"), os.date("%R"))) ---------------------------------------------------------------------- -- Contrôle si 1 Scène et déjà en cours -- ---------------------------------------------------------------------- local NbreScene = fibaro:countScenes() if NbreScene ~= 1 then; fibaro:debug("Il y a déjà une instance en cours... ") fibaro:abort(); end ---------------------------------------------------------------------- -- Vérification si les variables globales existe -- -- et Création ou Modification si Besoin -- ---------------------------------------------------------------------- VerifVG(VGJourNuit, "Jour", {"Jour", "Nuit"}) VerifVG(VGLeverSoleil, 0) VerifVG(VGCoucherSoleil, 0) ---------------------------------------------------------------------- -- Mise a jour de la variable VG Jour_Nuit au Démarrage de la Box -- -- Ou lors de la sauvegarde de la scène -- ---------------------------------------------------------------------- leverSoleil = fibaro:getValue(1, "sunriseHour") coucherSoleil = fibaro:getValue(1, "sunsetHour") UpdateJourNuit(VGJourNuit, os.date("%H:%M", os.time())) --------------------------------------------------------------------- -- Trie des Tables et récupération des valeurs min et maximum -- --------------------------------------------------------------------- -- Traitement de la Table TLever table.insert(TLever, 1, 0) -- ajout de 0 mn dans la table table.sort(TLever) local MiniLever = ((TLever[1]-30)) local MaxiLever = ((TLever[#TLever]+1)) -- Traitement de la Table TChoucher table.insert(TCoucher, 1, 0) -- ajout de 0 mn dans la table table.sort(TCoucher) local MiniCoucher = ((TCoucher[1]-30)) local MaxiCoucher = ((TCoucher[#TCoucher]+1)) --------------------------------------------------------------------- -- Test toute les minutes pour savoir si c'est jour ou nuit -- --------------------------------------------------------------------- while true do local j = 30 local osHeure = os.date("%H:%M", os.time()) leverSoleil = fibaro:getValue(1, "sunriseHour") coucherSoleil = fibaro:getValue(1, "sunsetHour") LeverCoucher(VGLeverSoleil, TLever, leverSoleil, "Jour") LeverCoucher(VGCoucherSoleil, TCoucher, coucherSoleil, "Nuit") j = calculPause(j, osHeure, MiniLever, MaxiLever, MiniCoucher, MaxiCoucher) fibaro:debug(string.format("Valeur du Sleep %s mn",j)) fibaro:sleep(j*60*1000); -- Pause en fonction de la valeur de J end A ceux qui vont utiliser cette scène, Merci de me faire un retour sur ce code...
  19. DECLARATIONS (Conditions/Triggers) { operator = "any", conditions = { -- tamper { id = 000, isTrigger = true, operator = "anyValue", property = "tamper", type = "device" } } } ACTIONS local trigger = sourceTrigger print("property:"..trigger.property) print("id:"..trigger.id) print("type:"..trigger.type) print("value:"..tostring(trigger.value))
  20. DECLARATIONS (Conditions/Triggers) { operator = "any", conditions = { -- proxymityStateChanged { id = 000, isTrigger = true, operator = "anyValue", property = "proxymityStateChanged", type = "device" } } } ACTIONS local trigger = sourceTrigger print("property:"..trigger.property) print("id:"..trigger.id) print("type:"..trigger.type) print("value:"..tostring(trigger.value)) Et pourquoi pas l'utilisation d'un quick app de type binary sensor en complément fibaro.call(0000,"breached", trigger.value)
  21. DECLARATIONS (Conditions/Triggers) { operator = "any", conditions = { -- buttonOneIsPressed { id = 000, isTrigger = true, operator = "anyValue", property = "buttonOneIsPressed", type = "device" }, -- buttonTwoIsPressed { id = 000, isTrigger = true, operator = "anyValue", property = "buttonTwoIsPressed", type = "device" }, -- buttonThreeIsPressed { id = 000, isTrigger = true, operator = "anyValue", property = "buttonThreeIsPressed", type = "device" } } } ACTIONS -- buttonOneIsPressed -- buttonTwoIsPressed -- buttonThreeIsPressed local trigger = sourceTrigger print("property:"..trigger.property) print("id:"..trigger.id) print("type:"..trigger.type) print("value:"..tostring(trigger.value))
  22. DECLARATIONS (Conditions/Triggers) { operator = "any", conditions = { -- input1 { id = 000, isTrigger = true, operator = "anyValue", property = "input1", type = "device" }, -- input2 { id = 000, isTrigger = true, operator = "anyValue", property = "input2", type = "device" } } } ACTIONS -- input1 -- input2 local trigger = sourceTrigger print("property:"..trigger.property) print("id:"..trigger.id) print("type:"..trigger.type) print("value:"..tostring(trigger.value))
  23. DECLARATIONS (Conditions/Triggers) { operator = "any", conditions = { -- firstRelayIsOpen { id = 000, isTrigger = true, operator = "anyValue", property = "firstRelayIsOpen", type = "device" }, -- secondRelayIsOpen { id = 000, isTrigger = true, operator = "anyValue", property = "secondRelayIsOpen", type = "device" } } } ACTIONS -- firstRelayIsOpen -- secondRelayIsOpen local trigger = sourceTrigger print("property:"..trigger.property) print("id:"..trigger.id) print("type:"..trigger.type) print("value:"..tostring(trigger.value))
  24. Je vous propose le script suivant qui émule la méthode "fibaro.call" moyennent quelques ajustements: Version 1.0.0 La prise en charge de callbacks (success, error) Le support du retard d'action (actuellement proposée par l' API mais non visible depuis la méthode intégrée call) Code lisible: -- Name: callAction -- Description: Trigger an action of the specified device -- Arg1: id [number] Device id -- Arg2: actionName [string] Action name -- Arg3: params [array] { delay [number], args [array] (option), success [function] (option), error [function] (option) } -- Return: nothing function callAction(id, actionName, params) local url = "http://127.0.0.1:11111/api/devices/" .. id .. "/action/" .. actionName local headers = { ["content-type"] = "application/json;charset=UTF-8", ["X-Fibaro-Version"] = "2", ["Cache-Control"] = "no-cache, no-store" } params = params or {delay=0, args={}} local args = params.args if (#args==0) then args = {{}} end assert(tonumber(params.delay), "callAction(id, actionName, delay, ...), delay argument must be an integer") local delay = tonumber(params.delay or 0) if (delay < 0) then delay = 0 end local arguments = { args = args, delay = delay } local http = net.HTTPClient({ timeout = 20000 }) http:request(url, { options = { headers = headers, method = "POST", data = json.encode(arguments) }, success = function(status) if (params.success ~= nil and type(params.success) == "function") then params.success(status.status, status.data) end end, error = function(error) if (params.error ~= nil and type(params.error) == "function") then params.error(error) end end }) end Version minifiée: Taux de compression du code: 48.53% function callAction(a,b,c)local d="http://127.0.0.1:11111/api/devices/"..a.."/action/"..b;local e={["content-type"]="application/json;charset=UTF-8",["X-Fibaro-Version"]="2",["Cache-Control"]="no-cache, no-store"}c=c or{delay=0,args={}}local f=c.args;if#f==0 then f={{}}end;assert(tonumber(c.delay),"callAction(id, actionName, delay, ...), delay argument must be an integer")local g=tonumber(c.delay or 0)if g<0 then g=0 end;local h={args=f,delay=g}local i=net.HTTPClient({timeout=20000})i:request(d,{options={headers=e,method="POST",data=json.encode(h)},success=function(j)if c.success~=nil and type(c.success)=="function"then c.success(j.status,j.data)end end,error=function(k)if c.error~=nil and type(c.error)=="function"then c.error(k)end end})end Un exemple d'utilisation pour illustrer: local params = { delay = 0, args = {"arg1", "arg2"}, success = function(status, data) print("success") print(status) end, error = function(error) print("error") end } -- Arg1: id [number] Device id -- Arg2: actionName [string] Action name -- Arg3: params [array] { delay [number], args [array] (option), success [function] (option), error [function] (option) } callAction(946, "turnOff", params) A venir dans une prochaine version: Sécurisation de l’exécution (via pcall) Une action poussée sur plusieurs périphériques Plusieurs actions poussées sur un périphérique Amusez-vous bien
  25. Krikroff

    QA FGIC-00X - Motion sensor

    L'idée de ce Quick App est de représenter sur la forme d'un module du type "binary sensor" l'état du détecteur de mouvement intégré à l' Intercom Fibaro C'est ultra basique, mais cela illustre de manière extrêmement simple comment un Quick App va permettre de donner de la visibilité à des valeurs, données, états etc. masqués et ceci sans grand effort, pour une fois ! Les méthodes du Quick App sont appelées via un fibaro.call depuis des scènes: https://www.domotique-fibaro.fr/topic/14116-utiliser-le-détecteur-de-proximité-de-lintercom-fibaro-dans-une-scène/ https://www.domotique-fibaro.fr/topic/14115-détection-du-tamper-de-lintercom-fibaro-dans-une-scène/ Le code à reporter dans l'éditeur LUA du QA est le suivant: -- Quick APP -- Name: QA FGIC-00X - Motion sensor -- Description: Fibaro Intercom motion sensor -- Type: Binary sensor function QuickApp:onInit() self:debug("onInit") end function QuickApp:breached(value) self:updateProperty("value", toboolean(value)) self:updateProperty("lastBreached", os.time()) end function QuickApp:tamper(tripped) if toboolean(tripped) then self:updateProperty("logTemp", "tamper tripped") end end function QuickApp:dead(value, reason) self:updateProperty("dead", toboolean(value)) self:updateProperty("deadReason", tostring(reason or "")) end do function toboolean(value) if (type(value) == "number") then return (value~=0) end return (not not value) end end Rien de sorcier Ensuite il faut extrapoler: Les méthodes pourraient également être appelées depuis une box externe au HC via des requêtes Les états pourraient être modifiés directement par le QA lui même à l'aide d'un code qui irait interroger des systèmes diverses (API d'un service en ligne, API d'un objet connecté etc.) Bref le champ des possibles est relativement vaste. Tout ceci est réalisé un petit peu à l'aveugle mais j'essaierai dans la mesure du possible de vous proposer des choses de plus en plus complexes
×