darklite44 Posté(e) le 23 mars 2015 Signaler Posté(e) le 23 mars 2015 Bonsoir, Grâce à l'Eco-Devices, on peut suivre ses consommations d'électricité. Aussi, aujourd'hui je met à jour manuellement un tableur en copiant les infos depuis le fichier CSV (http://@IP/protect/download/xdata.csv). J'aimerais automatiser le traitement mais GCE ne fournit pas ces informations via l'API. Donc est-il possible de parser un fichier CSV en LUA pour calculer une estimation de prochaine facture grâe à mon eco-Devices. J'ai essayé de telecharger le fichier pour commencer mais cela ne fonctionne pas. --[[ %% properties %% globals --]] -- Replace the value with ID of this virtual module selfId=fibaro:getSelfId(); ip = fibaro:get(selfId, 'IPAddress'); ECO = Net.FHttp(ip) local response, status, errorCode = ECO:GET("/protect/download/xdata.csv") fibaro:debug(response) fibaro:debug("####Debut#########################") -- check for error if errorCode == 0 then if tonumber(status) == 200 then -- enregistrement du retour de l API dans une table fibaro:debug(response) else fibaro:debug("HTTP response status: "..status); end else fibaro:debug("Communication error"); fibaro:log("Communication error"); fibaro:call(selfId, "setProperty", "ui.Msg.value", "Comm. error", os.date("%d %b - %X")); end --[[ -- local citylist = {ANNEE,MOIS,JOUR,T1_BASE,T1_HCHP,T1_HCHC,T1_EJPHN,T1_EJPHPM,T1_BBRHPJB,T1_BBRHCJB,T1_BBRHPJW,T1_BBRHCJW,T1_BBRHPJR,T1_BBRHCJR,T1_PMAX,T1_ISOUSC,T1_IMAX,Counter1,T2_BASE,T2_HCHP,T2_HCHC,T2_EJPHN,T2_EJPHPM,T2_BBRHPJB,T2_BBRHCJB,T2_BBRHPJW,T2_BBRHCJW,T2_BBRHPJR,T2_BBRHCJR,T2_PMAX,T2_ISOUSC,T2_IMAX,Counter2} -- local citylist = "ANNEE,MOIS,JOUR,T1_BASE" local citylist = {} for line in citylist do local city, region, coalition, coordinate_x, coordinate_y = line:match("%s*(.-),%s*(.-),%s*(.-),%s*(.-),%s*(.-)") citylist[#citylist + 1] = { city = city, region = region, coalition = coalition, coordinate_x = coordinate_x, coordinate_y = coordinate_y } end –]] function ParseCSVLine (line,sep) local res = {} local pos = 1 sep = sep or ',' while true do local c = string.sub(line,pos,pos) if (c == "") then break end if (c == '"') then -- quoted value (ignore separator within) local txt = "" repeat local startp,endp = string.find(line,'^%b""',pos) txt = txt..string.sub(line,startp+1,endp-1) pos = endp + 1 c = string.sub(line,pos,pos) if (c == '"') then txt = txt..'"' end -- check first char AFTER quoted string, if it is another -- quoted string without separator, then append it -- this is the way to "escape" the quote char in a quote. example: -- value1,"blub""blip""boing",value3 will result in blub"blip"boing for the middle until (c ~= '"') table.insert(res,txt) assert(c == sep or c == "") pos = pos + 1 else -- no quotes used, just look for the first separator local startp,endp = string.find(line,sep,pos) if (startp) then table.insert(res,string.sub(line,pos,startp-1)) pos = endp + 1 else -- no separator found -> use rest of string and terminate table.insert(res,string.sub(line,pos)) break end end end return res end text = ParseCSVLine (response,",") fibaro:debug("####Fin#########################") Je n'ai rien qui s'affiche comme si la variable response était vide : Merci 1
darklite44 Posté(e) le 16 avril 2015 Auteur Signaler Posté(e) le 16 avril 2015 On m'a proposé l'exemple suivant qui semble fonctionner pour parser une ligne ligne = '2015,4,14,0,33875763,36581093,0,0,0,0,0,0,0,0,0,30,42,4700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4700,' annee, mois, jour, hp, hc = ligne:match("(%d+),(%d+),(%d+),%d+,(%d+),(%d+),") Mon problème avec le CSV c'est commande gérer en LUA le téléchargement du fichier car le contenu n'est pas dans le body de la réponse HTTP. Du coup lorsque je parse, le contenu est nul. --[[ %% properties %% globals --]] -- Replace the value with ID of this virtual module selfId=fibaro:getSelfId(); ip = fibaro:get(selfId, 'IPAddress'); ECO = Net.FHttp(ip) local response, status, errorCode = ECO:GET("/protect/download/xdata.csv") fibaro:debug(response) fibaro:debug("####Debut#########################") -- check for error if errorCode == 0 then if tonumber(status) == 200 then -- enregistrement du retour de l API dans une table fibaro:debug(response) else fibaro:debug("HTTP response status: "..status); end else fibaro:debug("Communication error"); fibaro:log("Communication error"); fibaro:call(selfId, "setProperty", "ui.Msg.value", "Comm. error", os.date("%d %b - %X")); end fibaro:debug(response) Ce qui me donne en retour : [DEBUG] 09:20:40: ####Debut######################### Alors pour pour l'API JSON aucun problème avec le code suivant : local response, status, errorCode = ECO:GET("/api/xdevices.json?cmd=10")
darklite44 Posté(e) le 17 avril 2015 Auteur Signaler Posté(e) le 17 avril 2015 Bonsoir, J'ai progressé, j'arrive maintenant à télécharger et décoder une ligne du fichier . Je voudrais avoir de l'aide pour faire la boucle de lecture du buffer : --[[ %% properties %% globals --]] function getFileFromServer(tcp, path) r, s, e = tcp:GET(path); if (tonumber(s)~=200) then return 0, nil; else return string.len(r), r; end return nil; end -- CHECK SERVER fibaro:debug("---"); --setState(0, "CHECKING SERVER..."); -- connect to server fibaro:debug("Connecting to [192.168.1.10]..."); tcpSERVER = Net.FHttp("192.168.1.10", 80); if (not tcpSERVER) then fibaro:debug("SERVER ERROR! Skipping..."); else fibaro:debug("---"); size, content = getFileFromServer(tcpSERVER, "/protect/download/xdata.csv"); if (size>0) then fibaro:debug("Received file [" .. size .. " bytes]."); fibaro:debug("content [" .. content .. "]."); annee, mois, jour, hp, hc = content:match("(%d+),(%d+),(%d+),%d+,(%d+),(%d+),"); fibaro:debug("content:match=" .. annee .. "-" .. mois .. "-" .. jour .. ", HP:" .. hp .. ", HC:" .. hc); fibaro:debug("DONE!"); else fibaro:debug("Connection problem!"); end end Voilà ce que j'ai en retour [DEBUG] 23:24:21: --- [DEBUG] 23:24:21: Connecting to [192.168.1.10]... [DEBUG] 23:24:21: --- [DEBUG] 23:24:23: Received file [7730 bytes]. [DEBUG] 23:24:23: content:match=2015-1-21, HP:437439, HC:233912 [DEBUG] 23:24:23: DONE!
darklite44 Posté(e) le 20 avril 2015 Auteur Signaler Posté(e) le 20 avril 2015 Bonsoir, Est-ce quelqu'un peu tester mon code avec son eco-devices ? Je l'ai testé en mode HC : --[[ %% properties %% globals --]] function getFileFromServer(tcp, path) r, s, e = tcp:GET(path); if (tonumber(s)~=200) then return 0, nil; else return string.len(r), r; end return nil; end --[[ EXTRA FUNCTIONS ]]-- -- counting elements in array (table) function count(tab) local k,v,i; i=0; for k, v in pairs(tab) do i = i + 1; end return i; end -- print any variable content function printr(v,l,k) local d=function(t)fibaro:debug(t);end if(not l)then l=0;end local s=string.rep(string.char(0xC2,0xA0),(l*3)); local n="";if(k)then n=k.." = ";end if(v and type(v))then if(type(v)=="table")then d(s..n.."{");local i,j;for i,j in pairs(v)do printr(j,(l+1),tostring(i));end d(s.."}");elseif(type(v)=="function")then d(s..n..tostring(v).."() {");d(s.."}");elseif(type(v)=="userdata")then d(s..n..tostring(v).."() {");d(s.."}");elseif(type(v)=="string")then if(#v>50)then d(s..n.."String["..#v.."] = \""..string.sub(v,1,50).."\"...");else if(k)then v="\""..v.."\"";end d(s..n..tostring(v));end elseif(type(v)=="number")then d(s..n..tostring(v));else d(s..n..tostring(v).."["..type(v).."]");end else d(s..n.."{nil}");end end function trace(value) if (_trace) then return fibaro:debug(tostring(value)); end end function split(str, delim) local result,pat,lastPos = {},"(.-)" .. delim .. "()",1 for part, pos in string.gfind(str, pat) do table.insert(result, part); lastPos = pos end table.insert(result, string.sub(str, lastPos)) return result end ---============================================================ function padzero(s, count) return string.rep("0", count-string.len(s)) .. s end --======================================================================== -- get date parts for a given ISO 8601 date format (http://richard.warburton.it ) function get_date_parts(date_str) _,_,y,m,d=string.find(date_str, "(%d+)-(%d+)-(%d+)") return tonumber(y),tonumber(m),tonumber(d) end --==================================================== function getmonth(month) local months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } return months[tonumber(month)] end --==================================================== function getday_posfix(day) local idd = math.mod(day,10) return (idd==1 and day~=11 and "st") or (idd==2 and day~=12 and "nd") or (idd==3 and day~=13 and "rd") or "th" end --======================================================================== -- Note : date_str has to be ISO 8601 date format ie. yyyy-mm-dd -- function format_date(date_str, dateformat) local iyy, imm, idd if (date_str and date_str~="") then iyy, imm, idd = get_date_parts(date_str) dateformat = string.gsub(dateformat, "DDD", idd..string.upper(getday_posfix(idd))) dateformat = string.gsub(dateformat, "ddd", idd..getday_posfix(idd) ) dateformat = string.gsub(dateformat, "dd", padzero(idd,2)) dateformat = string.gsub(dateformat, "MMM", string.upper(getmonth(imm))) dateformat = string.gsub(dateformat, "mmm", getmonth(imm)) dateformat = string.gsub(dateformat, "mm", padzero(imm,2)) dateformat = string.gsub(dateformat, "yyyy", padzero(iyy,4)) dateformat = string.gsub(dateformat, "yy", string.sub(padzero(iyy,4),3,4)) else dateformat = "" end return(dateformat) end function split(str, pat) local t = {} -- NOTE: use {n = 0} in Lua-5.0 local fpat = "(.-)" .. pat local last_end = 1 local s, e, cap = str:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(t,cap) end last_end = e+1 s, e, cap = str:find(fpat, last_end) end if last_end <= #str then cap = str:sub(last_end) table.insert(t, cap) end return t end local energylist = {}; selfId=fibaro:getSelfId(); local ip = fibaro:get(selfId, 'IPAddress'); -- connect to server fibaro:debug("Connecting to [" .. ip .. "]..."); local tcpSERVER = Net.FHttp(ip, 80); HP_cost = 0.1572; HC_cost = 0.1096; local LastBill =os.time{year=2015, month=04, day=05}; if (not tcpSERVER) then fibaro:debug("SERVER ERROR! Skipping..."); else fibaro:debug("---"); size, content = getFileFromServer(tcpSERVER, "/protect/download/xdata.csv"); if (size>0) then fibaro:debug("Received file [" .. size .. " bytes]."); fibaro:debug("content [" .. content .. "]."); local table = split(content, "\n"); if(not l)then l=0; end for i,j in pairs(table)do -- test du pattern annee, mois, jour, hp, hc = j:match("(%d+),(%d+),(%d+),%d+,(%d+),(%d+),"); if(annee) then local seconds = os.time{year=annee, month=mois, day=jour}; local diff = tonumber(os.difftime(seconds, LastBill)); -- insertion dans le tableau day = annee .. "-" .. mois .. "-" .. jour f_day = format_date(day, "dd/mm/yy"); if(diff > 0) then energylist[#energylist + 1] = { date = f_day, hp = hp, hc = hc } end end end local max = count(energylist) -- comparer les valeurs pour calculer la facture fibaro:debug("Calcul sur la periode du " .. energylist[1].date .. " au " .. energylist[max].date); -- caclul conso hp_next_bill = tonumber( (energylist[max].hp - energylist[1].hp) /1000); hc_next_bill = tonumber( (energylist[max].hc - energylist[1].hc) /1000); -- calcul du cout hpc_next_bill = math.floor(hp_next_bill*HP_cost); hcc_next_bill = math.floor(hc_next_bill*HC_cost); next_bill = math.floor(hpc_next_bill + hcc_next_bill +(123.95/6) ); fibaro:debug("hp_next_bill: " .. hp_next_bill .. " kWH, " .. hpc_next_bill .. "€" ); fibaro:debug("hc_next_bill: " .. hc_next_bill .. " kWH, " .. hcc_next_bill .. "€" ); fibaro:debug("next_bill: " .. next_bill .. "€"); fibaro:debug("DONE!"); else fibaro:debug("Connection problem!"); end end Merci
darklite44 Posté(e) le 20 avril 2015 Auteur Signaler Posté(e) le 20 avril 2015 Il reste a améliorer cela en proposant par exemple un rapport du jour précédent avec notification un comparatif par rapport au même jour le mois précédent d'intégrer cela dans un module ...
Rocketlud Posté(e) le 20 avril 2015 Signaler Posté(e) le 20 avril 2015 Je test ca demain merci pour le partage darklite44;)
darklite44 Posté(e) le 20 avril 2015 Auteur Signaler Posté(e) le 20 avril 2015 Pour ceux qui ont une production, il faut modifier le pattern pour lire la valeur : annee, mois, jour, hp, hc, base_prod = ligne:match("(%d+),(%d+),(%d+),%d+,(%d+),(%d+),%d+,%d+,%d+,%d+,%d+,%d+,%d+,%d+,%d+,%d+,%d+,%d+,(%d+),");
Messages recommandés