Aller au contenu
971jmd

net.HTTPClient()

Recommended Posts

Salut a tous

 

je souhaite savoir si sous 4.510 pourquoi le code suivant ne fonctionne plus 

 

http = net.HTTPClient()
http:request("CODE_HTTP", {options = {
method = 'GET'
},
success = function(response) fibaro:debug("OK") end,
error = function(err) fibaro:debug("Error: " ..err) end
})

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour,

 

Manque un peu d'infos non ? Rassure moi, ce n'est pas ton code tel quel ? Sinon avec "CODE_HTTP" comme cela ca a déjà fonctionné ;-)

C'est ton code dans quel but ?

 

Je viens d'aller voir, suis en 4.510, par exemple le WATCHDOG de @Lazer fait du net.HTTPClient) et pas de soucis.

Partager ce message


Lien à poster
Partager sur d’autres sites

salut Pepite

oui effectivement j'ai pas précisé 

 

l'adresse suivante mes a jours une base SQL  :http://127.0.0.1:8080/fibaro/index3.php?nomdevice=lampe

ça fonctionne tres bien 

 

mai avec fibaro non:

   local http = net.HTTPClient()
http:request("http://127.0.0.1:8080/fibaro/index3.php?nomdevice=lampe", {options = {

method = 'GET'
},
success = function(response) fibaro:debug("OK") end,
error = function(err) fibaro:debug("Error: " ..err) end
})
[DEBUG] 08:17:48: Error: Connection refused
[DEBUG] 08:22:01: Error: Connection refused

 

pour info j'utilise WAMPSERVEUR

 

je pense que c le 127.0.0.1 que ne gère pas fibaro 

 


 

 

Partager ce message


Lien à poster
Partager sur d’autres sites
Il y a 2 heures, 971jmd a dit :

http://127.0.0.1:8080

je vias certainement dire ne grosse c..mais pour moi en l'ecrivant comme ceci tu lui demande d'aller sur son propre loopback.

 

Si sur WAMPserver, ton PC a bien une addresse IP non.

 

Essaie avec http://IPLANDUPC:8080/....

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites

j'ai tester avec :  

local http = net.HTTPClient()
http:request("192.168.0.44:8081/fibaro/index3.php?nomdevice=coco", {options = {

.

.

 

[DEBUG] 11:25:09: OK

 

mai rien ne bouge dans ma base SQL:15:

 

j'ai tester depuis mon iphone en local l'adresse 192.168.0.44:8081/fibaro/index3.php?nomdevice=coco

et rien 

 

Partager ce message


Lien à poster
Partager sur d’autres sites

j'ai trouver le problème, le WAP n'étais pas ouvert au réseaux local  

 

j'ai modifier le fichier, httpd.conf  de WAP...

 

    Order Deny,Allow
     Allow from all
     Allow from 127.0.0.1
     Allow from  192.168.0.44
     Allow from ::1
     Allow from localhost
</Directory>

Partager ce message


Lien à poster
Partager sur d’autres sites

Hello,

 

Je cherche à écrire une fonction générique pour executer une requête HTTPClient.

 

Voici mon code et j'ai quelques questions sur celui-ci :

 

1) Dans que cas il est conseillé d'encadrer la fonction http.request par une fonction  pcall() comme ceci ?

  • local ok = pcall(function() http:request(Query, {

2) Dans que cas il est conseillé d'encadrer la fonction json.decode, response.data par une fonction pcall() comme ceci ?

  • pcall(json.decode, response.data)

3) Dans mon code ci-dessous le traitement des données retournée par la requête est lancé à l'intérieur de la fonction. Est-ce possible (souhaitable) que le traitement des données soit fait à l'extérieur de la requête, soit par exemple :

  • success, data = GetData(Query)
  • if success then traitement_data(data) end
  • Sachant que dans le code ci-dessous, après la ligne if (status and data) then,  il aurait : return true, data et dans les autres cas return false

4) Comment intercepté que la requête est tombée timeout ? Ou fait-il mettre un test pour détecter le timeout et comment faire ce test.

 

Merci d'avance pour vos explications :13:

local TimeOut = 3000

function GetData(Query)
  local Synology = net.HTTPClient({ timeout = TimeOut })

  local ok = function() http:request(Query, {
      options = {
        method = 'GET',
        headers ={
              ["Content-Type"] = "application/json",
              ["Authorization"] = "BASIC "..User_code_API_Encode64},
        data = body
        },
      success = function(response)
      if response.status == 200 then
        Trace("blue","Traitement ok : ".."")
        local status, data = json.decode, response.data
        if (status and data) then
          Trace("orange"," OK -> Traitement des données")
        else
          Trace("orange"," Attention : Aucunes données à traiter")
        end
      else
        if response.status == 500 or response.status == 503 then
          Trace("orange","Erreur d'indisponibilité du serveur")
        else
          Trace("orange","Erreur requête serveur, response.status = "..response.status)
        end
      end
      end,
      error = function(err)
        Trace("orange","Erreur de reception de données, Erreur = ".. err)
      end
     })
  end
  if not(ok) then
    Trace("orange","Erreur dans l'exécution de http:request(Query...")
  end
end

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

1/ Je ne vois aucune raison pour laquelle il faudrait protéger un appel à http:request(), il s'agit d'une fonction qui s'exécute en asynchrone

 

2/ Idéalement il faudrait protéger l'appel à json.decode() à chaque fois qu'on décode un JSON provenant d'une source qu'on ne maitrise pas.... c'est à dire presque tout le temps en fait !

 

3/ Comme dit ci-dessus, et plusieurs fois sur le forum, c'est une fonction asynchrone, la suite de ton code doit s'exécuter à l'intérieur.

 

4/ Met des traces de partout, et constate par toi même ce qui se passe en cas de timeout... de mémoire ça doit être la fonction error() qui est exécutée.

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci Laser pour tes réponse,

 

Pour les scènes le fonction Net.FHttp() n'étant pas disponible, je suis obligé d'utiliser HTTPClient().

 

1) Sont-elle toutes le 2 deux asynchrone ?

il y a 7 minutes, Lazer a dit :

1/ Je ne vois aucune raison pour laquelle il faudrait protéger un appel à http:request(), il s'agit d'une fonction qui s'exécute en asynchrone

 

2) Tu veux dire que que l'appel à http:request() va me redonner la main alors que sont traitement ne serait pas terminé. C'est bien ce que tu veux dire par asynchrone ?

 

il y a 11 minutes, Lazer a dit :

4/ Met des traces de partout, et constate par toi même ce qui se passe en cas de timeout... de mémoire ça doit être la fonction error() qui est exécutée.

3) C'est ce que je supposais également. Mais comment faire le test ? Ralentir le serveur cible pour que le requête tombe en timeout ?

Partager ce message


Lien à poster
Partager sur d’autres sites

Je viens de trouver ton post sur le sujet :

 

 

 

 

Il y a probablement les réponses mes questions ;)

 

Partager ce message


Lien à poster
Partager sur d’autres sites

1/ Non, seule Net.Fhttp (dispo seulement dans les VD) est syncrhone, elle s'exécute linéairement de façon traditionnelle.

 

2/ Oui, tu reprends la main tout de suite, donc il FAUT que ton code se termine immédiatement après pour que les fonctions success() et error() appelées en calback par http:request() puisse s'exécuter. C'est pareil que pour la fonction settimeout() en fait. La suite de ton code doit se trouver dans success()

 

3/ Mettre des fibaro:debug() de partout dans ton code, et faire une requête vers un serveur qui ne répond pas. Ou qui est trop lent à répondre, utilise pour cela l'option timeout décrite dans mon tuto que tu as trouvé.

Partager ce message


Lien à poster
Partager sur d’autres sites

1) Il n'est donc pas possible de créer une fonction générique HTTPClient() puisque chaque fois que l'utilise il faut qu'elle contienne les traitements spécifique que l'on veut exécuter. C'est bien ça ?

 

2) est-ce que l'on peut dans success() lancer une autre fonction HTTPClient()  ?

 

3) si oui à la question précédente ça devient vite compliquer à programmer, je prends l'exemple suivant :

  • On se connect à un serveur via un ID de connection mais que celui-ci ne fonction plus
  • On se reconnect au un serveur via un login et mot de passe pour obtenir un nouvel ID
  • On se reconnect au au serveur serveur via le nouvel ID et l'on execute une requête pour obtenir des premiers infos via une API.
  • On se reconnect au au serveur serveur via le nouvel ID et l'on execute une requête pour obtenir des deuxièmes infos via une API.
  • On se reconnect au au serveur serveur via le nouvel ID et l'on execute une requête pour obtenir des Xièmes infos via une API.

Cela veux dire que le code doit être structuré de façon à cascader chacune des étapes ?

Ca m'a l'air bien lourd ou il y a quelque chose qui m'échappe.

 

4) Comment s'assurer que l'appel à une fonction HTTPClient() est terminée pour poursuivre les traitements suivants ?

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

1/ Si c'est possible si tu lui passes des arguments spécifiques. Regarde comment j'ai traité ce sujet dans la scène MusicCast.

 

2/ Normalement oui, mais tu peux le tester. Mais si tu veux traiter le point 1, il vaut mieux appeler une fonction qui ensuite appellera à son tour HTTPClient. Encore une fois, voir MusicCast.


3/ Le cas du login est traité dans la scène de détection de présence via Unifi.

Il faut effectivement bien structurer son code.

 

4/ Tu ne peux pas, relis mon tuto.... je ne vais pas me répéter

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 22 minutes, Lazer a dit :

4/ Tu ne peux pas, relis mon tuto.... je ne vais pas me répéter

En faite ma question j'aurais du préciser ma question. Comment ext-ce que l'on fait dans le cas d'une de l'appel à la fonction HTTPClient() dans une boucle ?

Partager ce message


Lien à poster
Partager sur d’autres sites

Tu ne peux pas, il faut revoir tout ton code.... c'est la fonction success() appelée en callback de HTTPClient() qui doit à son tour effectuer la suite des actions.

On peut imaginer passer un tableau de paramètre avec la liste des actions à effectuer, et un pointeur pour savoir où on en est.

Partager ce message


Lien à poster
Partager sur d’autres sites

Je viens de regarder ta scene : Yamaha MusicCast - Scene v1.0.lua et ses VD associé.

 

C'est exactement cette mécanique que je souhaite mettre en place une scene qui :

  • Sollicite une API via des requêtes HTTPClient() 
  • reçoit des ordres (action) en provenance d'un ensemble de VD
  • met à jour des labels de ses même VD en fonction des ordres reçus

Maintenant, je vais devoir comprendre son fonctionnement pour l'adapter à mon besoin. C'est une très bonne base de départ :13:

 

Mais j'ai un peu de mal a comprendre le fonctionnement des lignes ci-dessous dans tes fonctions ( getAPI() et getAPI() ), notamment la ligne setTimeout(function() callback(verb, jsonTable) end, 0)

-- Execute callback function
if callback and type(callback) == "function" then
  if debug then
    Message("purple", "getAPI() : callback...")
  end
  setTimeout(function() callback(verb, jsonTable) end, 0)
end

Je suppose que pour comprendre qu'il faut l'associer à l'exemple du code suivant :

if debug then
	Message("pink", "link() : call postAPI(setClientInfo)")
end
	setTimeout(function() postAPI("/YamahaExtendedControl/v1/dist/setClientInfo", "setClientInfo", link, {group_id=group_id, zone={_parameters[client_vd_s_id].zone}}, client_ip, client_port) end, 0)

elseif verb == "setClientInfo" then

Je l'impression que c'est bien là le fond du sujet évoqué précédemment ?

 

Pourrais-tu STP m'expliquer un peu le principe de fonctionnement et notamment au regard de nos échanges précédents ?

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai avancé sur mon code, mais je n'arrive à faire fonctionner les appels via la fonction setTimeout. Elle n'execute pas la fonction les appels aux fonction getAPI() ou postAPI().

 

SI je prends l'exemple de ta fonction : power ci-dessous, dans la ligne :

 

        setTimeout(function() getAPI("/YamahaExtendedControl/v1/".._parameters[VD_s_id].zone.."/setPower?power=".._value, "setPower", power) end, 0)

 

 l'appel de la fonction getAPI ne s'execute pas. J'ai mis des traces au début de la fonctions getAPI() mais elles n'apparaissent pas.

 

Si j'enlève la partie setTimeout(function() de la façon suivante :

 

        getAPI("/YamahaExtendedControl/v1/".._parameters[VD_s_id].zone.."/setPower?power=".._value, "setPower", power)

 

dans ce cas, je rentre bien dans la fonction getAPI (avec affichage de mes traces), mais là, l'appel à la fonction :

 

httpClient:request("http://" .. ip .. ":" .. tostring(port) .. url, {

 

ne provoque aucun retour, ni dans success, ni error.

 

Je ne vois vraiment pas d'où vient le PB. Tu pourrais STP m'indiquer la cause ?

 

local function power(verb, data)

	if not verb then
		if debug then
			Message("pink", "power() : call getAPI(setPower)")
		end
		setTimeout(function() getAPI("/YamahaExtendedControl/v1/".._parameters[VD_s_id].zone.."/setPower?power=".._value, "setPower", power) end, 0)
	elseif verb == "setPower" then
		Success()
	else
		Die('Warning : verb "' .. (verb or "???") .. '" unknown')
	end

end -- function

 

Partager ce message


Lien à poster
Partager sur d’autres sites

@Lazer Laisse tomber mon message ci-dessus. J'ai trouvé ;)

 

J'ignore pourquoi, mais lorsque je lance la scène depuis un VD, ça fonctionne :60:

 

Mais lorsque je lance la scène en manuel, ça ne marche pas. Je sais ce n'est pas l'objet de ce type de scène qui doivent être lancé depuis une autre scène ou VD.

 

Mais maintenant, je m'arrache les cheveux pour construire la structure du code pour que les enchainements se fassent bien :huh:

 

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

Désolé, pas dispo plus tôt.

Bon tu avances, c'est bien :)

 

Aucune idée pour le lancement manuel, c'est étrange, ça ne devrait pas être différent d'un appel depuis le VD, car c'est bien un lancement manuel qu'il fait.

La différence, c'est que le VD passe des paramètres, tandis que ton lancement manuel ne donne aucun paramètre.

Dans ton code, il faut que tu récupères et testes les paramètres de la scène dès le début de son exécution..... il y a un tuto pour ça aussi sur le forum :)

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai un peu de mal à comprendre comment organiser le code pour executer l'enchainement suivant chaque fois que la scène est appelée par une action.

  1. On se connect au serveur pour récupérer des paramètres de l'API nécessaire pour se connecter au serveur, si la requête est bone, on passe au point 2
  2. On se reconnect au serveur via un ID de connection stocker dans une VG mais que celui-ci ne fonctionne pas/plus ou qu'il n'est pas encore renseigné dans la VG l'on passe au point 2.1 sinon au point 3
    1. On se reconnect au serveur via un login et mot de passe pour obtenir un nouvel ID qui est stocker dans une VG
  3. On se reconnect au serveur serveur via l'ID et les paramètres de l'API et l'on execute une requête pour soit (En fait mon action demandé pas le VD)
  • obtenir des infos de l'API
  • executer d'une fonction de lAPI
  • modère une propriété de l'API

Sachant que les paramètre de l'API peuvent changer dans le temps, idem pour l'ID, il peut ne plus être valable après un certain temps.

Autant les paramètre d'API, je pourrais les charger dans une VG depuis le main des VD puisqu'il n'est pas nécessaire de s'identifier sur le serveur pour obtenir ces paramètres.

Mais pour l'ID je souhaiterais éviter de devoir mettre dans chacun des mes VD mon login et mot de passe pour générer un nouvel ID et le stocker dans une VG.

Sachant comme tu t'en doute, l'objectif principal est de mettre tous (ou le maximum) le code lié à l'API dans la scène et alléger de fait les VD au maximum.

 

a) Compte-tenu mode asynchrone, est-ce que cela signifie que pour chaque des actions lancées par les VD, je dois dans la scène créer un fonction correspondante qui devra contenir l'ensemble de la séquence énoncée ci-dessus ? 

Excepte la recherche des paramètres si elle est ramenée dans le main du VD (ce que souhaiterais néanmoins éviter

b) Est-ce qu'il y une limite du nombre d'imbrications des séquences d'appels à l'API via des requêtes HTTPClient()  ?

c) Comment organiser ces imbrications avec le principe de callback des fonctions ?

 

Nota c'est vraiment lourdingue de ne pas avoir mis à disposition la fonction Net.FHttp() dans les scènes. Il font ch... chez Fibaro. Cela nous oblige du coup à monter du code d'une complexité, s'il on veut limiter sa redondance :15:

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

a) euh là je ne suis pas certain de bien comprendre ce que tu veux faire....

 

b) aucune idée ! En tout cas perso je n'ai pas été limité. Il faut tester.

 

c) idem que point (a), ce que tu veux faire n'est pas clair pour moi.

 

 

Mais de ce que tu décris, je dégage 2 choses principales :

  • pouvoir configurer tous les paramètres en un point unique, par exemple la Main Loop du VD, laquelle se charge ensuite de stocker ces paramètres dans une variable globale (à grand coup de json.encode())
    Toute cette logique est utilisée dans mon VD MusicCast, entre la Main Loop, ses Boutons, et la scène unique (je précise bien scène unique, car cette même scène est appelée par TOUS les boutons de TOUS les VD (un VD par enceinte/ampli à domotiser)).

    Plus précisément :
    • dans la Main Loop du VD :
      • il y a toute la logique de création de la VG, du stockage des données, et même une vérification périodique de sa validité (protection contre les N/A bien connus qui se produisent lorsque l'utilisateur va enregistrer manuellement le panneau de variable).
      • il y a également, en bonus, la détection automatique de l'ID de la scène, ce qui évite à l'utilisateur de devoir le renseigner manuellement
    • dans chaque bouton de VD :
      • Appel de la scène avec des arguments
    • dans la scène :
      • récupération des arguments

        ==> Donc pour moi, il n'y a pas vraiment de difficulté sur ce point là, tu peux simplement récupérer et adapter ce que j'ai fait.
         
  • enchainer les actions asynchrones dans la scène entre les appels aux fonctions HTTPClient() et settimeout()
    Là encore, tout cela est utilisé dans la scène MusicCast, avec tout un tas de paramètres passés en argument des fonctions, afin que prendre les bonnes décisions (quelle action effectuer ensuite, etc).
    Justement là comme je ne comprends pas ce que tu veux faire, c'est à toi de bien comprendre la logique de fonctionnent, et de le traduire pour tes propres actions.

    ==> Là, c'est à toi de jouer

Partager ce message


Lien à poster
Partager sur d’autres sites

Tout ce que tu viens de dire je l'avais bien compris. Et c'est bien sur tes VD et ta Scène MusicCast que je capitalise. J'ai garder la logique d'ensemble.

 

Dans ton code MusicCast tu n'utilises pas non plus le Main Loop des VD pour solliciter l'API. Tout est dans ta scène et c'est bien ça que je cherche à reproduire. Mettre tout le code concernant l'API dans la Scène.

 

Mon questionnement vient en fait sur l'écriture d'une fonction (Action) dans la scène, lorsque celle-ci nécessite des appels à l'API en cascade à l'intérieur de celle-ci. Cf. les différentes étapes du traitement que j'exposais précédemment, dont chacune des étapes doit correspond re à une fonction afin de pouvoir utiliser le mécanisme de callback pour connaitre le résultat de la fonction (étape).

 

Effectivement, de part le mécanisme de traitement asynchrone, c'est difficile à expliquer.

 

Merci néanmoins pour tes explications précieuses :13:

 

Modifié par MAM78

Partager ce message


Lien à poster
Partager sur d’autres sites

×