Help wanted adapting "Capturing Energy Usage with Lua Script

Moderator: leecollings

Post Reply
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Help wanted adapting "Capturing Energy Usage with Lua Script

Post by elmortero »

Hi there,

I've been trying to adapt https://www.domoticz.com/wiki/Capturing ... ua_Scripts to match my setup but keep getting error "bad argument #1 to 'match' (string expected, got nil)"

I have the EM6601 (recognised as NQ-92021) which is called Elec_meter and has idx 88

What I want is same as in the wikipage (or maybe write the output to a virtual meter, in order not to write any data to he actual -working-meter)
User avatar
jvdz
Posts: 2267
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by jvdz »

It would help when you post the line you get the error on. :)
In general when a nil is returned it is likely that the devicename doesn't exists in case the is a line like this one:

Code: Select all

   nhousePower, houseEnergy = string.match(otherdevices_svalues['Household'], "(%d+%.*%d*);(%d+%.*%d*)")
The devicename has the be exact and is case sensitive.

Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by elmortero »

The error:
2015-12-21 19:20:12.183 LUA: elecmeter : 0.000;17346192.000
2015-12-21 19:20:12.183 Error: EventSystem: .../pi/domoticz/scripts/lua/script_device_elecmeter_log.lua:76: bad argument #1 to 'match' (string expected, got nil)
Hi, posting the info.
Would really appreciate the help
The devices (all virtual except elecmeter)
IDX Name Type SubType Data
-----------------------------------------------------------------------------
88 elecmeter General kWh 17346.206 kWh
109 Exported RFXMeter RFXMeter counter 0.000 kWh
108 Imported RFXMeter RFXMeter counter 0.000 kWh
107 Household General kWh 0.000 kWh

the script:

Code: Select all



function timedifference(s)
   year = string.sub(s, 1, 4)
   month = string.sub(s, 6, 7)
   day = string.sub(s, 9, 10)
   hour = string.sub(s, 12, 13)
   minutes = string.sub(s, 15, 16)
   seconds = string.sub(s, 18, 19)
   t1 = os.time()
   t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
   difference = os.difftime (t1, t2)
   return difference
end
 
function timeCount(numSec)
   local nSeconds = numSec
   if nSeconds == 0 then
      return  "0seconds"
   else
      local sTime = ""
      local nHours = math.floor(nSeconds/3600)
      local nMins = math.floor(nSeconds/60 - (nHours*60))
      if(nHours > 0) then
         sTime = sTime .. nHours
         if(nHours == 1) then
            sTime = sTime .. "hour "
         else
            sTime = sTime .. "hours "
         end         
      end
      if(nMins > 0) then
         sTime = sTime .. nMins
              if(nMins == 1) then
            sTime = sTime .. "minute "
         else
            sTime = sTime .. "minutes "
         end         
      end
      local nSecs = math.floor(nSeconds - nHours*3600 - nMins *60) 
      if(nSecs > 0) then 
         sTime = sTime .. nSecs
              if(nSecs == 1) then
            sTime = sTime .. "second"
         else
            sTime = sTime .. "seconds"
         end
      end
      return sTime 
   end
end
 
function update(device, id, power, energy, index)
   if (index < 4) then
      commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy}
   else
      commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. energy}
   end
   return
end   
 
commandArray = {}
 
local voltage = 243
local houseid = 107
local usedid = 108
local generatedid = 109 
 
if devicechanged['elecmeter'] then
   elec = otherdevices_svalues['elecmeter']
   print('elecmeter : '..elec)
   words = {}
   for w in string.gmatch(elec, "%d+%.?%d*") do
      words[#words + 1] = w
    end
	  nhousePower, houseEnergy = string.match(otherdevices_svalues['Household'], "(%d+%.*%d*);(%d+%.*%d*)")
   usedEnergy = string.match(otherdevices_svalues['Imported'], "%d+%.*%d*")
   interval = timedifference(otherdevices_lastupdate['elec_switch'])

   -- convert interval in seconds into hours
   interval = interval / 3600
-- calculate power (voltage * current) and cumulative energy (current energy + power * time)
-- for each monitored line 
   housePower = voltage * tonumber(words[1])
   houseEnergy = tonumber(houseEnergy) + (housePower * interval)
   currentPower = housePower
   if (currentPower > 0) then
      usedEnergy = tonumber(usedEnergy) + (interval * currentPower)
   end
   if (currentPower > 0) then
      update("Imported", usedid, 0, usedEnergy, 4)
   else
      update("Exported", generatedid, 0, generatedEnergy, 4)
   end
end
return commandArray
User avatar
jvdz
Posts: 2267
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by jvdz »

The error is telling you that this part returns a nil: otherdevices_svalues['Household']
I don't have this in my setup but you could add these 2 lines above the line in error just to get some debug info:

Code: Select all

	print(" otherdevices['Household']:",otherdevices['Household'])
	print(" otherdevices_svalues['Household']:",otherdevices_svalues['Household'])
	nhousePower, houseEnergy = string.match(otherdevices_svalues['Household'], "(%d+%.*%d*);(%d+%.*%d*)")
Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by elmortero »

Hi Jos,

Did that and also manually entered a 'starting value' -> the current reading of 'elecmeter' in Household in order not to have zero as a value.
Error logs now shows:
2015-12-21 20:30:13.403 LUA: elecmeter : 0.000;17346332.000
2015-12-21 20:30:13.403 LUA: otherdevices['Household']:
2015-12-21 20:30:13.403 LUA:
2015-12-21 20:30:13.404 LUA: otherdevices_svalues['Household']:
2015-12-21 20:30:13.404 LUA: 1;17346290
2015-12-21 20:30:13.404 Error: EventSystem: .../pi/domoticz/scripts/lua/script_device_elecmeter_log.lua:4: bad argument #1 to 'sub' (string expected, got nil)
---> line 4 is from the original script

Thanks for your help!
User avatar
jvdz
Posts: 2267
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by jvdz »

:?: .. but that is a total different error you are getting now so entering the initial value fixed that?
Could it be this line is now causing the error?:

Code: Select all

   interval = timedifference(otherdevices_lastupdate['elec_switch'])
Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by elmortero »

Updated the script, basically working now.
Except: it triggers itself again and thus creating a zero value.

Code: Select all

function timedifference(s)
   year = string.sub(s, 1, 4)
   month = string.sub(s, 6, 7)
   day = string.sub(s, 9, 10)
   hour = string.sub(s, 12, 13)
   minutes = string.sub(s, 15, 16)
   seconds = string.sub(s, 18, 19)
   t1 = os.time()
   t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
   difference = os.difftime (t1, t2)
   return difference
end
 
function timeCount(numSec)
   local nSeconds = numSec
   if nSeconds == 0 then
      return  "0seconds"
   else
      local sTime = ""
      local nHours = math.floor(nSeconds/3600)
      local nMins = math.floor(nSeconds/60 - (nHours*60))
      if(nHours > 0) then
         sTime = sTime .. nHours
         if(nHours == 1) then
            sTime = sTime .. "hour "
         else
            sTime = sTime .. "hours "
         end         
      end
      if(nMins > 0) then
         sTime = sTime .. nMins
              if(nMins == 1) then
            sTime = sTime .. "minute "
         else
            sTime = sTime .. "minutes "
         end         
      end
      local nSecs = math.floor(nSeconds - nHours*3600 - nMins *60) 
      if(nSecs > 0) then 
         sTime = sTime .. nSecs
              if(nSecs == 1) then
            sTime = sTime .. "second"
         else
            sTime = sTime .. "seconds"
         end
      end
      return sTime 
   end
end
 


     function update(device, id, power, energy, index)
    	if (index < 3) then   
         commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy}
         else
         commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. energy}
        end
    return
end

commandArray = {}
 
local houseid = 112
local usedid = 111
 
if devicechanged['elecmeter'] then
   elec = otherdevices_svalues['elecmeter']
   print('elecmeter : '..elec)
   words = {}
   for w in string.gmatch(elec, "%d+%.?%d*") do
      words[#words + 1] = w
    end
     nhousePower, houseEnergy = string.match(otherdevices_svalues['elecmeter'], "(%d+%.*%d*);(%d+%.*%d*)")
     updateuse = houseEnergy
     usedEnergy = string.match(otherdevices_svalues['Household'], "%d+%.*%d*")
     consumed = houseEnergy - usedEnergy
     interval = timedifference(otherdevices_lastupdate['elec_switch'])
	  print ('houseEnergy : '..houseEnergy)
	  print ('usedEnergy : '..usedEnergy)
      print ('diff : '..consumed)   
      print ('interval : '..interval)
      rate = (consumed / interval) * 3600	 
	  print ('rate : '..rate)
      commandArray['elec_switch'] = 'On'
      update("Household", houseid, 0, updateuse, 3)
	  update("Imported", usedid, 0, rate, 4)
	  end
return commandArray
The log:
2015-12-22 18:34:54.509 LUA: elecmeter : 0.000;17348642.000
2015-12-22 18:34:54.510 LUA: houseEnergy : 17348642.000
2015-12-22 18:34:54.510 LUA: usedEnergy : 17348630.000
2015-12-22 18:34:54.510 LUA: diff : 12
2015-12-22 18:34:54.510 LUA: interval : 285
2015-12-22 18:34:54.510 LUA: rate : 151.57894736842

Until here quite ok, need some cleanup of the "rate" value.

But then it triggers again, while elecmeter has not been updated at this point and thus creating a zero difference between the readings and therefor calculating a Zero rate (--> calculate consumption per hour)
2015-12-22 18:34:54.514 EventSystem: Script event triggered: /home/pi/domoticz/scripts/lua/script_device_elecmeter_log.lua
2015-12-22 18:34:54.547 LUA: elecmeter : 0.000;17348642.000
2015-12-22 18:34:54.547 LUA: houseEnergy : 17348642.000
2015-12-22 18:34:54.547 LUA: usedEnergy : 17348642.000
2015-12-22 18:34:54.547 LUA: diff : 0
2015-12-22 18:34:54.547 LUA: interval : 285
2015-12-22 18:34:54.547 LUA: rate : 0
2015-12-22 18:34:54.550 EventSystem: Script event triggered: /home/pi/domoticz/scripts/lua/script_device_elecmeter_log.lua

Got the feeling I am almost there, but not completely.
Maybe I shouldn't have thrown myself in LUA just yet.

Any hint welcome.
User avatar
jvdz
Posts: 2267
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by jvdz »

Could it be you have 2 devices called "elecmeter" and does it always runs 2 times?
You could simply test for consumed > 0 and only update when it contains a value greater than 0:

Code: Select all

function timedifference(s)
   year = string.sub(s, 1, 4)
   month = string.sub(s, 6, 7)
   day = string.sub(s, 9, 10)
   hour = string.sub(s, 12, 13)
   minutes = string.sub(s, 15, 16)
   seconds = string.sub(s, 18, 19)
   t1 = os.time()
   t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
   difference = os.difftime (t1, t2)
   return difference
end
 
function timeCount(numSec)
   local nSeconds = numSec
   if nSeconds == 0 then
      return  "0seconds"
   else
      local sTime = ""
      local nHours = math.floor(nSeconds/3600)
      local nMins = math.floor(nSeconds/60 - (nHours*60))
      if(nHours > 0) then
         sTime = sTime .. nHours
         if(nHours == 1) then
            sTime = sTime .. "hour "
         else
            sTime = sTime .. "hours "
         end         
      end
      if(nMins > 0) then
         sTime = sTime .. nMins
              if(nMins == 1) then
            sTime = sTime .. "minute "
         else
            sTime = sTime .. "minutes "
         end         
      end
      local nSecs = math.floor(nSeconds - nHours*3600 - nMins *60) 
      if(nSecs > 0) then 
         sTime = sTime .. nSecs
              if(nSecs == 1) then
            sTime = sTime .. "second"
         else
            sTime = sTime .. "seconds"
         end
      end
      return sTime 
   end
end
 
function update(device, id, power, energy, index)
	if (index < 3) then   
		commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. power .. ";" .. energy}
	else
		commandArray[index] = {['UpdateDevice'] = id .. "|0|" .. energy}
	end
    return
end

commandArray = {}
 
local houseid = 112
local usedid = 111
 
if devicechanged['elecmeter'] then
	elec = otherdevices_svalues['elecmeter']
	print('elecmeter : '..elec)
	words = {}
	for w in string.gmatch(elec, "%d+%.?%d*") do
		words[#words + 1] = w
    end
	nhousePower, houseEnergy = string.match(otherdevices_svalues['elecmeter'], "(%d+%.*%d*);(%d+%.*%d*)")
	updateuse = houseEnergy
	usedEnergy = string.match(otherdevices_svalues['Household'], "%d+%.*%d*")
	consumed = houseEnergy - usedEnergy
	interval = timedifference(otherdevices_lastupdate['elec_switch'])
	rate = (consumed / interval) * 3600    
	print ('rate : '..rate)
	if consumed > 0 then
		print ('houseEnergy : '..houseEnergy)
		print ('usedEnergy : '..usedEnergy)
		print ('diff : '..consumed)   
		print ('interval : '..interval)
		commandArray['elec_switch'] = 'On'
		update("Household", houseid, 0, updateuse, 3)
		update("Imported", usedid, 0, rate, 4)
	end
end
return commandArray
Jos
Last edited by jvdz on Tuesday 22 December 2015 19:10, edited 1 time in total.
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Sc

Post by elmortero »

Thanks Jos !

I was just about to edit my last post, after I've seen the light about the checking for consumed > 0

Now checking if by any chance I have a double elecmeter.
Update: no double "elecmeter". But not an issue for now, with the greater than zero check
Really appreciate your help.

update: found out why the script gets triggered twice everytime:
when the meter sends it's update, it sends it twice. No clue why that is or how to ignore the second one
2015-12-23 12:05:00.292 (RaZberry) General/kWh (elecmeter)
2015-12-23 12:05:00.798 (RaZberry) General/kWh (elecmeter)
2015-12-23 12:20:14.225 (RaZberry) General/kWh (elecmeter)
2015-12-23 12:20:14.261 (RaZberry) General/kWh (elecmeter)
tnegun
Posts: 11
Joined: Tuesday 27 December 2016 16:19
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.6328
Location: Ireland
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Script

Post by tnegun »

Hi elmortero,

Sorry to drag up an old thread but I'm trying to achieve similar to you and it looks like this script fits the bill but I have a couple of questions!

The device to collect the usage is type Electric Instant + Counter?

In your script you have these devices elecmeter, elec_switch, Household and Imported.

elecmeter is the meter returning the current watts being used right?
elec_switch is a virtual switch to track when we last got an update from elecmeter.
Household is the device to collect the usage
I'm not sure what Imported is ?

thanks
tnegun
Posts: 11
Joined: Tuesday 27 December 2016 16:19
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.6328
Location: Ireland
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Script

Post by tnegun »

So I managed to cobble together a solution myself. I'm using an Electric Instant + Counter Device with the Energy Read option set to computed.

I'm using this script

Code: Select all

commandArray = {}
if devicechanged['IT Demand'] then
	power = otherdevices_svalues['IT Demand']
	--commandArray['UpdateDevice'] = 31 .. "|0|" .. power  --Not working
	--commandArray['UpdateDevice'] = 31 .. "|" .. power -- Alternate format not working 
	commandArray['OpenURL'] = 'http://172.20.0.7/json.htm?type=command&param=udevice&idx=31&svalue='..power..'' -- works as expected 
end
return commandArray
I'd like to get commandArray['UpdateDevice'] working however if I use either of the examples above I loose the current power and used power from the device and I see "0,value of power" e.g. If power used is 430 watts the device no longer displays 430 watts in the title and is the body both counters loose their units and I see 0,430.0 . I guess I'm passing the values it the wrong order or type? Using commandArray['OpenURL'] line works everytime as expected.
elmortero
Posts: 247
Joined: Sunday 29 November 2015 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.9639
Location: Spain
Contact:

Re: Help wanted adapting "Capturing Energy Usage with Lua Script

Post by elmortero »

I think that it is related to the limitations mentioned in the last post of this topic: viewtopic.php?t=12628
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests