Franco268 Posté(e) le 30 janvier 2023 Signaler Posté(e) le 30 janvier 2023 Hello, Je cherche un peu d'aide pour reprendre un code HC2 et le mettre sur ma HC3. Je souhaite faire 3 requetes pour obtenir le statut de mon UPS. Le probleme est que je n'arrive pas à découper les réponses... La réponse de mes 2 premières demandes se retrouve dans la première réponse et la dernière demande, dans la seconde réponse. J'ai fais des tentatives de sleep, d'imbriquer les "read" dans les "Write", mais rien n'y fait Pouvez vous m'aider? J'ai beaucoup lu sur le forum et utiliser l'exemple Fibaro HC3. Mai je ne comprend pas comment synchroniser les réponses avec les demandes -- Quick App template for handling the TCP device debug = true selfIp = "192.168.100.2"; -- the IP of this virtual device selfPort = 3493; -- the dedicated port for this virtual device tcpCommandVarGet = "GET VAR"; -- TCP command to get variable tcpCommandUpsName = "UPS"; -- Name of UPS timeOut = 5; -- Time-out attempts for setting up a connection timeOutTime = 1; -- Time-out time for setting up a connection, in seconds scrollDelaySec = 2; -- Raport scrolldelay in seconds instanceValueWrite = 1; -- Instancevalue to write (must be an unique number per button in VD) instanceValueComError = 8; -- Instancevalue when communication error is reported instanceValueDecError = 9; -- Instancevalue when decoding received data error is reported instanceValue = 0; isOnline = 0; enter = string.char(0x0d, 0x0a); receivedTable = {}; function QuickApp:BtnMaj_onReleased(event) if debug then self:debug("BtnMaj_onReleased(event)") end --self:send("Some command for on\n") -- sending data to the device. In a normal implementation it will be a code with an appropriate command. self:send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."ups.status"..enter) self:send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."battery.charge"..enter) self:send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."battery.runtime"..enter) end -- the method for sending data to the device -- the method can be called from anywhere function QuickApp:send(strToSend) self.sock:write(strToSend, { success = function() -- the function that will be triggered when the data is correctly sent self:debug("data sent: " ..strToSend) end, error = function(err) -- the function that will be triggered in the event of an error in data transmission self:debug("error while sending data") end }) end -- method for reading data from the socket -- since the method itself has been looped, it should not be called from other locations than QuickApp:connect function QuickApp:waitForResponseFunction() self.sock:read({ -- reading a data package from the socket success = function(data) self:onDataReceived(data) -- handling of received data self:waitForResponseFunction() -- looping of data readout end, error = function() -- a function that will be called in case of an error when trying to receive data, e.g. disconnecting a socket self:debug("response error") self.sock:close() -- socket closed fibaro.setTimeout(5000, function() self:connect() end) -- re-connection attempt (every 5s) end }) end -- a method to open a TCP connection. -- if the connection is successful, the data readout loop will be called QuickApp:waitForResponseFunction() function QuickApp:connect() self.sock:connect(self.ip, self.port, { -- connection to the device with the specified IP and port success = function() -- the function will be triggered if the connection is correct self:debug("connected") self:send("VER"..enter) self:waitForResponseFunction() -- launching a data readout "loop" end, error = function(err) -- a function that will be triggered in case of an incorrect connection, e.g. timeout self.sock:close() -- closing the socket self:debug("connection error") fibaro.setTimeout(5000, function() self:connect() end) -- re-connection attempt (every 5s) end, }) end -- function handling the read data -- normally this is where the data reported by the device will be handled function QuickApp:onDataReceived(data) data = tostring(data) self:debug("onDataReceived", data) if data ~= "" then table.insert(receivedTable, data); if debug then self:debug("Table filled, row number: "..#receivedTable) end; if #receivedTable ~= 0 then --and isOnline == 1 and instanceValue == instanceValueWrite if receivedTable[#receivedTable] ~= nil then textValueStart = tostring(string.find(receivedTable[#receivedTable], '"')); self:debug("textValueStart: ", textValueStart) if textValueStart ~= "nil" then textValueEnd = tostring(string.find(receivedTable[#receivedTable], '"', textValueStart+1)); self:debug("textValueEnd: ", textValueEnd) if textValueEnd ~= "nil" then textValue = string.sub(receivedTable[#receivedTable], textValueStart+1, textValueEnd-1); self:debug("textValue: ", textValue) if string.find(receivedTable[#receivedTable], "ups.status") ~= nil then self:updateView("LblStatus", "text", "Statut: " ..textValue) end if string.find(receivedTable[#receivedTable], "battery.charge") ~= nil then self:updateView("LblBatLevel", "text", "Battery Level: " ..textValue .."%") end if string.find(receivedTable[#receivedTable], "battery.runtime") ~= nil then self:updateView("LblBatTime", "text", "Battery Time: " ..textValue .." sec") end self:updateView("upsReportLabel", "text", "Value "..textValue.." written."); hub.sleep(scrollDelaySec*1000); else instanceValue = instanceValueDecError if debug then hub.debug("Test Tag", "Error decoding value: missing second quotesign...") end; end else instanceValue = instanceValueDecError if debug then hub.debug("Test Tag", "Error decoding value: missing first quotesign...") end; end else instanceValue = instanceValueDecError if debug then hub.debug("Test Tag", "Error decoding value: not really found something...") end; end else instanceValue = instanceValueDecError if debug then hub.debug("Test Tag", "Error decoding value: no text to decode...") end; end if instanceValue == instanceValueDecError then self:updateView("upsReportLabel", "text", "Decoding error: value not written to GV"); hub.sleep(scrollDelaySec*1000); end else self:updateView("LblStatus", "text", "Statut: No response!"); self:updateView("LblBatLevel", "text", "Battery Level: No response!"); self:updateView("LblBatTime", "text", "Battery Time: No response!"); instanceValue = instanceValueComError if debug then self:debug("Error: No data received!") end; --hub.sleep(scrollDelaySec*1000); end end function QuickApp:onInit() self:debug("onInit") self.ip = self:getVariable("ip") self.port = tonumber(self:getVariable("port")) self.sock = net.TCPSocket() -- creation of a TCPSocket instance self:connect() end
Lazer Posté(e) le 30 janvier 2023 Signaler Posté(e) le 30 janvier 2023 Alors, sans prendre le temps d'étudier ton code, il faut que tu comprennes la notion d'asynchronisme. Le code en cours d'exécution se termine, puis un nouveau thread est démarré qui va prendre le relai, etc. Donc il faut enchainer les appels de fonction dans le retour de la fonction success() à chaque appel. Etc. Et surtout ne jamais utiliser de sleep() Exemple ici pour des requêtes HTTP, mais c'est pareil pour le TCPsocket, sauf que tu dois faire plus d'enchainement connect => success => transmit => success => receive => success => disconnect...
Franco268 Posté(e) le 3 février 2023 Auteur Signaler Posté(e) le 3 février 2023 J'ai tenté d'enchainé toutes mes étapes. Mais je ne comprends pas du tout le résultat. Les 2 premières commandes sont envoyés. Mais pas la troisième. Le truc de fou, c'est qu'en réponse, j'ai dans UN SEUL retour la réponse de la seconde requête ET de la TROISIEME! Celle qui n'a pas été envoyé! J'ai essayé de mettre mon code au plus simple mais je ne comprends pas l'erreur. -- Quick App template for handling the TCP device debug = true selfIp = "192.168.100.2"; -- the IP of this virtual device selfPort = 3493; -- the dedicated port for this virtual device tcpCommandVarGet = "GET VAR"; -- TCP command to get variable tcpCommandUpsName = "UPS"; -- Name of UPS enter = string.char(0x0d, 0x0a); function QuickApp:BtnMaj_onReleased(event) self:debug("BtnMaj_onReleased(event)") self:Send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."ups.status"..enter) self:Send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."battery.charge"..enter) self:Send(tcpCommandVarGet.." "..tcpCommandUpsName.." " .."battery.runtime"..enter) end function QuickApp:Send(request) self.sock = net.TCPSocket() -- creation of a TCPSocket instance self.sock:connect(self.ip, self.port, { -- connection to the device with the specified IP and port success = function() -- the function will be triggered if the connection is correct self:debug("connected") self.sock:write(request, { success = function() -- the function that will be triggered when the data is correctly sent self:debug("data sent: " ..request) self.sock:read({ -- reading a data package from the socket success = function(data) data = tostring(data) self:debug("onDataReceived", data) self.sock:close() -- socket closed end, error = function() -- a function that will be called in case of an error when trying to receive data, e.g. disconnecting a socket self:debug("response error") self.sock:close() -- socket closed end }) end, error = function(err) -- the function that will be triggered in the event of an error in data transmission self:debug("error while sending data") end }) end, error = function(err) -- a function that will be triggered in case of an incorrect connection, e.g. timeout self.sock:close() -- closing the socket self:debug("connection error") end, }) end function QuickApp:onInit() self:debug("onInit") self.ip = self:getVariable("ip") self.port = tonumber(self:getVariable("port")) end Résultat: [03.02.2023] [15:15:02] [DEBUG] [QUICKAPP70]: onInit [03.02.2023] [15:15:05] [TRACE] [QUICKAPP70]: UIEvent: {"elementName":"BtnMaj","deviceId":70,"eventType":"onReleased","values":[null]} [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: BtnMaj_onReleased(event) [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: connected [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: connected [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: connected [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: data sent: GET VAR UPS ups.status [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: data sent: GET VAR UPS battery.charge [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: onDataReceived VAR UPS battery.runtime "3000" battery.charge "100" [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: error while sending data [03.02.2023] [15:15:05] [DEBUG] [QUICKAPP70]: onDataReceived
Lazer Posté(e) le 3 février 2023 Signaler Posté(e) le 3 février 2023 (modifié) Dans le log on voit que 3 connect et 2 write ont effectués avant même que tu tentes de faire le 1er read. Celui-ci fait immédiatement un close de la socket, donc le 3ème write n'est plus possible. Normal, car tout s'exécute en asynchrone (donc tu ne peux pas maitriser le timing), cependant dans le code de ton bouton tu as lancé 3 séquences (asynchrones donc) en simultané. Ce n'est pas bon, il faut lancer uniquement la 1ère, puis quand elle est complètement terminée (dans le succes() du dernier read(), alors tu peux enchainer sur la suite) Voir à ce sujet la discussion récente ici : Modifié le 3 février 2023 par Lazer
Franco268 Posté(e) le 9 février 2023 Auteur Signaler Posté(e) le 9 février 2023 Merci, pour le lien. L'imbrication est acquis... mon petit bout de code tourne. Prochaine étape le "join" pour du multi requête
Messages recommandés