Aller au contenu

Messages recommandés

Posté(e)

Bonjour,

Je cherche a passer une valeur par une url quand un detecteur de mouvement de la Hc se declence

http://(HS3 URL)/HomeSeer_REST_API.aspx?function=setdevicevaluebyid&param1=(Device Reference ID)&param2=(Value you want to set)

Je suis parti d'une scene en mode bloc pour transformer en lua

 

Merci

Posté(e)

J'avance tout doucement. Je veux executer une url en passant des valeur quand mon detecteur 137 detecte quelque chose:

--[[
%% properties
137 value
%% globals
--]]
local value=tonumber(fibaro:getValue(137, "value"))
--local value=60
local hs_id=1018
local startSource = fibaro:getSourceTrigger();

if ( value> 0 ) then
-- on crée une instance HC2 et on appel le pc
  HC2 = Net.FHttp("192.168.1.3:8081");
-- on met a jour le device virtuel distant
response = HC2:GET("/Api_Rest/HomeSeer_REST_API.aspx?function=setdevicevaluebyid&param1="..hs_id.."&param2="..value)
fibaro:debug(response)
end

Mais j'ai l'erreur suivante:

[ERROR] 18:53:20: line 13: attempt to index global 'Net' (a nil value)

 
 
Si quelqu'un peut jeter un oeil, merci
Posté(e)

Hello, la fonction est toujours supportée, mais uniquement dans un module virtuel (enfin je crois pour ce dernier truc).

 

Par ailleurs, la fonction get retourne un tableau donc essaie 

response, status, errCode = HC2:GET("/Api_Rest/HomeSeer_REST_API.aspx?function=setdevicevaluebyid&param1="..hs_id.."&param2="..value)
Posté(e)

Merci pour cette réponse J'ai modifié le code dela maniere suivante:

-[[
%% properties
137 value
%% globals
--]]
local value=tonumber(fibaro:getValue(137, "value"))
local hs_id=1018
local startSource = fibaro:getSourceTrigger()
if ( value> 0 ) then
-- on crée une instance HC2 et on appelle le pc
HC2 = Net.FHttp("192.168.1.3:8081")
-- on met a jour le device virtuel distant
--response = HC2:GET("/Api_Rest/HomeSeer_REST_API.aspx?function=setdevicevaluebyid&param1="..hs_id.."&param2="..value)
response, status, errCode = HC2:GET("/Api_Rest/HomeSeer_REST_API.aspx?function=setdevicevaluebyid&param1="..hs_id.."&param2="..value)
fibaro:debug(response)
fibaro:debug('Envoi vers Homeseer Mouvement Salon')
end 

J'ai aussi dégagé les ";" qui viennent du mode bloc mais que je retrouve pas dans les tutoriels.

Pas de progres l'erreur est sur la ligne 12

HC2 = Net.FHttp("192.168.1.3:8081")
[ERROR] 09:17:20: line 12: attempt to index global 'Net' (a nil value)
[ERROR] 09:17:21: line 12: attempt to index global 'Net' (a nil value)
[ERROR] 09:18:00: line 12: attempt to index global 'Net' (a nil value)
Posté(e)

Essaye comme ça :

HC2 = Net.FHttp("192.168.1.3", 8081)

Tu es en v4.018 ?

Si ça ne fonctionne pas, c'est que la fonction est supprimée de cette version comme je le disais.

Posté(e)

Éventuellement, tu crées une variable globale

 

Tu crées une scène basique qui va modifier la valeur de cette variable en cas de détection de mouvement.

 

Tu testes ta valeur globale dans le main loop d'un module virtuel et si la condition est remplie, alors exécution de ton code.

 

Et le tour est joué.

Posté(e)

ah oui c'est vrai dans une scène ce n'est pas supporté.

 

Plus simple : depuis la scène, tu peux directement cliquer sur le bouton d'un module virtuel, ce qui évite de créer une variable globale inutilement, évite une boucle dans un module virtuel qui tourne en rond pour pas grand chose, et surtout permet une réactivité immédiate :

fibaro:call(<id>, "pressButton", "1")
Posté(e)

Une question Maître Yoda, j'ai lu ça et làque le main loop était gourmand en ressource, parce qu'un appel toutes les 3 secondes. Mais une scène classique, faut bien aussi qu'elle soit lancée pour tester la valeur des triggers. Alors y a t-il vraiment une différence ??? Je pose cette question, parce que je suis en train de programmer un module virtuel pour gérer mon chauffage. Ce module s'appuie sur le panneau de chauffage, pour pouvoir agir facilement sans modifier du code. Mais pour le moment, je n'ai pas trouvé d'autres façons d'accéder au panneau autrement que par l'api. (je pense finir ce soir et publier mon code). Mais s'il y a un risque de fatiguer nos HC2, peut être faut que je cherche une autre solution...

Posté(e)

Le principe de la main loop d'un module virtuel c'est effectivement de boucler automatiquement avec un sleep de 3 secondes.

L'idée c'est que si tu effectue tout un tas de vérifications, pour finalement ne rien faire parce que les conditions ne sont pas remplies, alors du as fait travailler le processeur pendant quelques millisecondes pour rien. Multiple ça par le nombre de modules virtuels, et tu fait travailler inutilement la box. C'est pour ça qu'on dit qu'une main loop est gourmande en ressource.

 

A l'opposé, une scène est inactive tant qu'elle n'est pas déclenchée par un événement (trigger). C'est la HC2 qui active la scène uniquement lorsque c'est nécessaire.

Attention toutefois, une scène peut aussi comporter une boucle (à  programmer soit même, par exemple avec un simple "while true do ....... end" comme le fait GEA de Steven ou d'autres scènes). A ce moment là , on en revient au principe de fonctionnement d'une main loop de module virtuel.

 

Le truc c'est qu'il y a des situations où on ne peut pas faire autrement que d'avoir une boucle infinie, que ce soit dans un main loop ou une scène.

Par exemple : de nombreuses variables à  gérer, dont on doit conserver la valeur d'un passage à  un autre dans le code... Il serait trop fastidieux de stocker tout ça en variables globales.

Il n'y a donc pas d'autres choix que d'utiliser ces fameuses boucles, et on doit alors coder intelligemment pour éviter de surcharger le processeur.

Par exemples : éviter de conserver le sleep(3000) si un sleep(60000) est suffisant, essayer de limiter les tâches à  effectuer à  chaque passage dans la boucle, éviter de faire appel à  des fonctions buggées (Net.FHTTP suivi de json.decode)

 

Après il faut relativiser, un programme correctement écrit ne dure pas plus de quelques millisecondes, donc c'est négligeable, et ce n'est pas çà  qui va fatiguer la HC2, qui est relativement puissante. L'exemple du script GEA est un bon exemple de la complexité possible tout en conservant d'excellente performances. Les différents modules virtuels de Krikroff également.

 

Dans ton exemple de panneau de chauffage, tu n'as pas d'autre choix que de faire appel à  l'API, donc utilisation des fonctions Net.FHTTP() et json.decode()... et cela plantera forcément au bout de quelques passages dans la boucle.

La solution est donc de mettre ta routine principale dans un bouton d'un module virtuel, et la main loop se chargera d'appeler le bouton à  intervalle régulier.

Posté(e)

Je t'explique en avant première mon projet. 

 

J'ai 2 chaudières, mais comme de plus en plus de monde finalement (beaucoup ajoute un mode alternatif à  un mode existant). Le panneau de chauffage, bien fait pour programmer des plages horaires par zone relativement facilement, mais un peu obscure si on veut chauffer qu'une partie de son logement à  certaines heures (genre, je veux 21° le matin dans ma petite chambre le matin au réveil, mais pas utile d'avoir une telle température dans tout mon logement). Bref, programmer un module me semblait la seule solution. 

 

Par ailleurs, ça me permet de prendre en compte les jours fériés, ma présence ou non dans mon logement. J'ai testé aujourd'hui, à  priori, ça fonctionne plutôt bien. 

 

Pour chaque zone, j'ai créé une variable prédéfinie, nommée id_Chauf_pièce contenant D_XXX pour définir le déclencheur de chauffage (chauffage ou poêle à  pelées), P_pièce pour définir à  quelle zone le programme de chauffage se rattache la pièce, T_XXX pour définir la sonde de température de référence et Z_XXX pour définir l'id d'un éventuel vanne Danfoss (Z_000, pas de sonde).

 

Puisqu'il s'agit de chauffage, j'ai mis un sleep à  5 minutes (pas pertinent de tester toutes les 3 secondes). 

 

Avant d'ouvrir une rubrique, je te met le code en avant première, s'il y a des commentaires...

 

Je posterai dans quelques jours le code mais il me faut encore commenter tout ça, pour que ça soit plus clair

function EnumZone()
   local a, b, c = 0;
   local p = { };
   local i = 0 ;
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/panels/heating");
   a, b = string.find(result, "name", 1);
   while a do
      b, c = string.find(result, ",", a + 6);
      i = i + 1 ;
      table.insert(p, string.sub(result, a + 7, b -2));
      a = b + 1;
      a, b = string.find(result, "name", a);
   end
   return p;
end

function IdZone(piece)
   local a, b, c = 0;
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/panels/heating");
   a, b = string.find(result, piece, debut);
   return string.sub(result, a-12, a-10);
end

function TempActuelle(piece)
   local a, b, c = 0;
   local T = "";
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/globalVariables");
   a, b = string.find(result, "id_Chauf_" .. piece, 1);
   b, c = string.find(result, "T_", a);
   T = string.sub(result, b + 2, b + 4);
   return fibaro:getValue(T, "value");
end

function TempConsigne(Id)
   local a, b, c, d = 0;
   local T, h, heureCourante, e, programme  = "";
   local jour = "";
   local currentDate = os.date("*t");
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/panels/heating?id=" .. Id);
   if fibaro:getGlobalValue("JourChome") == "Oui" then
      jour = "sunday"
   else
      jour = string.lower(os.date("%A"))
   end
   a, b = string.find(result, jour, 1);
   b, c = string.find(result, "}}", a);
   programme = string.sub(result, a-1, ;
   b = 1;
   if tonumber(currentDate.hour)<10 then e = "0" else e = "" end;
   heureCourante = e .. currentDate.hour
   if tonumber(currentDate.min)<10 then e = "0" else e = "" end;
   heureCourante = heureCourante .. ":" .. e .. currentDate.min
   for a = 1, 4 do
      h = "";
      b, c = string.find(programme, "hour", b+1);
      c, d = string.find(programme, ",", ;
      --fibaro:debug(programme);
      if tonumber(string.sub(programme, b+6, c-1))<10 then e = "0" else e = "" end;
      h = e .. string.sub(programme, b+6, c-1);
      b, c = string.find(programme, "minute", ;
      c, d = string.find(programme, ",", ;
      if tonumber(string.sub(programme, b+8, c-1))<10 then e = "0" else e = "" end;
      h = h .. ":" .. e .. string.sub(programme, b+8, c-1);
      if h < heureCourante then
          c, d = string.find(programme, "temperature", ;
          e, d = string.find(programme, "}", ;
          T = string.sub(programme, c + 13, e-1);
      end
   end
   return T 
end

function EnumDeclencheur()
   local a, b = 0;
   local Declencheur = "";
   local Exist = false;
   local i, j = 0;
   local D = { };
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/globalVariables");
   a, b = string.find(result, "D_", 1);
   while a do
      i = i + 1 ;
      Declencheur = string.sub(result, a + 2, a + 4);
      j = 1;
      Exist = false;
      while D[j] do
        if D[j] == Declencheur then Exist = true end;
        j = j + 1;
      end
      if not Exist then table.insert(D, Declencheur) end;
      a, b = string.find(result, "D_", a + 2);
   end
   return D;
end

function DeclencheurZone(piece)
   local a, b = 0;
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/globalVariables");
   a, b = string.find(result,"id_Chauf_" .. piece, 1);
   a, b = string.find(result, "D_", a);
   return string.sub(result, a + 2, a + 4);
end

function EnumSourceZ(piece)
   local a, b, c, d  = 0;
   local Cons = { };
   local HC2= Net.FHttp("192.168.1.20");
   HC2:setBasicAuthentication("admin", "xxxxxx");
   local result, status, errorCode = HC2:GET("/api/globalVariables");
   a, b = string.find(result, "id_Chauf_" .. piece, 1);
   a, b = string.find(result, "Z_", a);
   while a do
      table.insert(Cons, string.sub(result, a + 2, a + 4))
      d = a;
      a, b = string.find(result, "Z_", a + 2);
      if a then 
        b, c = string.find(result, "id_Chauf_", d);
        if b then
           if b < a then a = nil end;
        end;
      end
   end
   return Cons;
end

if fibaro:getGlobalValue("Present") == "Oui" then
   local i,j,k = 1;
   local piece = EnumZone();
   local declencheur = EnumDeclencheur();
   local besoin = {};
   local idDeclencheur = {};
   local nbDeclencheur = 0;

   while piece[i] do
      j = 1;
      EnumSource = EnumSourceZ(piece[i]);
      while EnumSource[j] do
         if EnumSource[j] ~= "000" then
            fibaro:call(EnumSource[j], "setTargetLevel", TempConsigne(IdZone(piece[i])))
         end
         j = j + 1;
      end
   
      l = 0;
      for k = 1, nbDeclencheur do
         if idDeclencheur[k] == DeclencheurZone(piece[i]) then l = k end;
      end;
      if l == 0 then 
         nbDeclencheur = nbDeclencheur + 1;
         l = nbDeclencheur;
         idDeclencheur[l] = DeclencheurZone(piece[i])
      end 
      if tonumber(TempActuelle(piece[i])) < (tonumber(TempConsigne(IdZone(piece[i]))) - 0.7) then
         besoin[l] = "turnOn"
      else
         if not besoin[l] and tonumber(TempActuelle(piece[i])) < tonumber(TempConsigne(IdZone(piece[i]))) then 
            besoin[l] = "standby" 
         else
            if not besoin[l] then
               besoin[l] = "turnOff"
            end
         end;
      end;  
      
      i = i + 1;
   end;

   for i = 1, nbDeclencheur do
      if besoin[i] ~= "standby" then fibaro:call(idDeclencheur[i], besoin[i]) end;
   end;
end;
fibaro:sleep(5*60*1000);

Posté(e)

(j'avoue, j'interroge souvent l'API pour obtenir le même résultat, mais en terme de clarté, de compréhension des fonctions, ça aide beaucoup et vu la rapidité d'obtention des infos, ça ne me semble pas forcément un problème)

Posté(e)

Je n'ai pas relu le code en détail, d'autres le feraient mieux que moi (Krikroff, Steven, ...)

 

Puisque tu as un sleep de 5 minutes, il n'y aura aucun problème de performance.

 

Le seul risque, c'est le plantage et donc l'arrêt de la main loop.

En effet, tu as tout mis dans la main loop (le code principal et les autres fonctions).

A la longue (sur plusieurs jours ou semaines), pour une raison ou une autre, un bug peu arriver et à  ce moment là  la main loop sera complètement stoppée par sécurité par la HC2. Donc tu n'auras plus de chauffage.

Ce qui provoque un plantage à  coups sà»r c'est l'emploi de Net.FHTTP() puis GET() et json.decode(). Dans le cas présent tu n'utilises pas le json.decode donc le risque semble limité, mais sait-on jamais ce qui peut se produire...

Il serait plus sécurisant de mettre tout ton code dans un bouton de ton module virtuel, et ne conserver que ceci dans la main loop :

fibaro:call(fibaro:getSelfId(), "pressButton", "1")
fibaro:sleep(5*60*1000)

PS : le point-virgule est inutile en LUA, donc je te conseille de les enlever (ou de les mettre à  toutes les lignes) pour plus de cohérence.

  • Upvote 1
Posté(e)

Je ne suis pas un pro, mais initié par le turbo pascal, donc je me plie tant bien que mal àune certaine discipline, mais là, le compilateur est plus souple...

Posté(e)

En 4.018, les plantages semblent plus limités (par rapport à4.017). Naïvement, pour moi, jeune adepte de la HC2, du code reste du code... J'ai sans doute beaucoup àapprendre

Posté(e)

Après, un certain Krikroff ou Steven a dit que c'était aberrant de rebouter sa box pour pallier à  certains plantages, donc pour le moment, je me dis que ça reste perfectionable, mais j'ai foi à  la HC2

Posté(e)

Ouch, le Turbo Pascal j'ai pratiqué il y a très longtemps.... c'était un peu trop strict à  mon gout, même si ça ne fait pas de mal.

 

Redémarrer la box ce n'est jamais nécessaire.... (en tout cas, je n'ai personnellement jamais eu besoin depuis 1 an), les seuls reboot sont dus aux mises à  jour, ou à  mes travaux sur mon installation électrique.

 

Par contre, un virtual device qui plante, ça arrive régulièrement, et avec la méthode que je t'ai donné, c'est fiable à  99,99999% au moins :)

Ca peut aussi planter à  cause de son propre code : par ex, on oublie toujours de tester la valeur d'au moins une variable avant de l'employer.

×
×
  • Créer...