Aller au contenu

Messages recommandés

Posté(e)
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
  • Upvote 1
  • 3 semaines après...
Posté(e)

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")
Posté(e)

Bonsoir,

 

J'ai progressé, j'arrive maintenant à  télécharger et décoder une ligne du fichier :60: . 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!
Posté(e)

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
Posté(e)

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
  • ...
Posté(e)

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+),");
×
×
  • Créer...