<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Capturing_Energy_Usage_with_Lua_Scripts</id>
	<title>Capturing Energy Usage with Lua Scripts - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Capturing_Energy_Usage_with_Lua_Scripts"/>
	<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Capturing_Energy_Usage_with_Lua_Scripts&amp;action=history"/>
	<updated>2026-09-19T01:28:14Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://wiki.domoticz.com/index.php?title=Capturing_Energy_Usage_with_Lua_Scripts&amp;diff=4427&amp;oldid=prev</id>
		<title>ThinkPad at 07:37, 3 September 2015</title>
		<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Capturing_Energy_Usage_with_Lua_Scripts&amp;diff=4427&amp;oldid=prev"/>
		<updated>2015-09-03T07:37:55Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== The Owl Energy Monitor and Domoticz ==&lt;br /&gt;
&lt;br /&gt;
The Owl CM113 energy monitor has 3 sockets into which standard Owl current clamps can be attached.  In my house I have seperate electrical circuits for the general household usage, the ground source heatpump usage and my solar photovoltaic generation, with household on line 1, heatpump on line 2 and solar on line 3 of the Owl CM113.&lt;br /&gt;
&lt;br /&gt;
Domoticz is very smart and plots graphs of all three current sources as watts power on a single log graph from the utility page.  The graph is smart, so clicking on the legends for each individual power usage will hide that plot, allowing any combination of plots to be produced.&lt;br /&gt;
&lt;br /&gt;
== Generating Additional Information ==&lt;br /&gt;
&lt;br /&gt;
However, it would nice to be able to see how much energy we are using in a number of different ways, solar energy that was generated yesterday, household energy that was used yesterday and the amount of energy the heatpump used yesterday.  Of course the other two things that mater is the cost i.e how much energy we are importing (household + heatpump - solar) and how smug we should be feeling by donating green energy to everybody else i.e. how much energy we are exporting (solar - household + heatpump).  Looking at daily figures doesn&amp;#039;t give me these figures, as if I only use 20kWhs in the morning while generating nothing and generate 20kWhs in the afternoon while using nothing, my overall energy usage will be nothing, but I will be billed for 20kWhs and have donated 20kWhs.  So this needs to be an instaneous calculation which will record the instaneous import or export of energy.&lt;br /&gt;
&lt;br /&gt;
== Setting Up Domoticz ==&lt;br /&gt;
&lt;br /&gt;
In Domoticz under Setup / Hardware having created a Dummy hardware then using Create Virtual Sensor - create 3 Electric (Instant + Counter) meters (Household, Heatpump, Solar) and 2 Counters (Imported, Exported). Once all these devices have been set-up then go to the Setup / Devices page and make a record of each id to change the script below so it will work on your machine.&lt;br /&gt;
&lt;br /&gt;
== Calculating Energy Usage with Lua ==&lt;br /&gt;
&lt;br /&gt;
The two Domoticz meters expect to be fed a cumulative value of energy.  So the approach I have taken is to take the current readings and multiply that by a set voltage to give the instaneous power.  I then calculate the energy used the last reading as the multiple of the current power times the time since the last energy reading was returned.  Then adding this new energy used to the cumulative energy usage returned from the virtual meters, gives a new total energy usage.&lt;br /&gt;
&lt;br /&gt;
As the time between Owl current readings is not uniform, I can not gaurentee that energy calculated will be entirely accurate as it will not fit up short time fluctuations and by not averaging between the previous and current power levels.  However any error is relatively small and will not stop the various meters from giving a good handle on energy usage and generation.&lt;br /&gt;
&lt;br /&gt;
== Updating Energy Usage with Lua ==&lt;br /&gt;
&lt;br /&gt;
The simplest method is purely to send the current power and the cumulative energy via commandArray[&amp;#039;UpdateDevice&amp;#039;], but only 1 value per script can be sent this way:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
commandArray[&amp;#039;UpdateDevice&amp;#039;] = id .. &amp;quot;|0|&amp;quot; .. power .. &amp;quot;;&amp;quot; .. energy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Since version 1.700 of Domoticz it has been possible to send multiple updates via this route:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
commandArray[1] = {[&amp;#039;UpdateDevice&amp;#039;] = houseid .. &amp;quot;|0|&amp;quot; .. housepower .. &amp;quot;;&amp;quot; .. houseenergy}&lt;br /&gt;
commandArray[2] = {[&amp;#039;UpdateDevice&amp;#039;] = pumpid .. &amp;quot;|0|&amp;quot; .. pumppower .. &amp;quot;;&amp;quot; .. pumpenergy}&lt;br /&gt;
commandArray[3] = {[&amp;#039;UpdateDevice&amp;#039;] = solarid .. &amp;quot;|0|&amp;quot; .. solarpower .. &amp;quot;;&amp;quot; .. solarenergy}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See the [[Events]] page for the full context.&lt;br /&gt;
&lt;br /&gt;
For simpler meter then the command is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
commandArray[4] = {[&amp;#039;UpdateDevice&amp;#039;] = exportedid .. &amp;quot;|0|&amp;quot; .. exportenergy}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A Script to Process Energy Usage ==&lt;br /&gt;
&lt;br /&gt;
The script ~/domoticz/scripts/lua/script_device_owl_log.lua is activated everytime the Owl energy meter transmits a new set of current readings.&lt;br /&gt;
&lt;br /&gt;
The scripts read in the old cumulative energy for each of the 5 channels from the dummy energy meters.&lt;br /&gt;
&lt;br /&gt;
The currents from the Owl device are then converted to instanteous power by multiplying by the fixed voltage and the time since the last update is also returned.   Multiplying the time since the last update by the instaneous power gives the energy used since last accumlation.  The total energy can now be calculate by adding the new energy to the old energy.  The instaneous power and the cumulative energy are then sent back to Domoticz. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- /home/pi/domoticz/scripts/lua/script_device_owl_log.lua&lt;br /&gt;
-- Takes the instaneous current values from an Owl power monitor&lt;br /&gt;
-- For each current calculates instaneous power, checks when it was last called to work&lt;br /&gt;
-- out energy used over that time&lt;br /&gt;
-- Add current energy usage to previous energy usage and accumulates energy in devices&lt;br /&gt;
-- Updates energy monitor dummy devices in Domoticz - Household, Heat Pump, Solar&lt;br /&gt;
-- Plus two caculated values - Exported and Imported&lt;br /&gt;
&lt;br /&gt;
function timedifference(s)&lt;br /&gt;
   year = string.sub(s, 1, 4)&lt;br /&gt;
   month = string.sub(s, 6, 7)&lt;br /&gt;
   day = string.sub(s, 9, 10)&lt;br /&gt;
   hour = string.sub(s, 12, 13)&lt;br /&gt;
   minutes = string.sub(s, 15, 16)&lt;br /&gt;
   seconds = string.sub(s, 18, 19)&lt;br /&gt;
   t1 = os.time()&lt;br /&gt;
   t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}&lt;br /&gt;
   difference = os.difftime (t1, t2)&lt;br /&gt;
   return difference&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function timeCount(numSec)&lt;br /&gt;
   local nSeconds = numSec&lt;br /&gt;
   if nSeconds == 0 then&lt;br /&gt;
      return  &amp;quot;0seconds&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      local sTime = &amp;quot;&amp;quot;&lt;br /&gt;
      local nHours = math.floor(nSeconds/3600)&lt;br /&gt;
      local nMins = math.floor(nSeconds/60 - (nHours*60))&lt;br /&gt;
      if(nHours &amp;gt; 0) then&lt;br /&gt;
         sTime = sTime .. nHours&lt;br /&gt;
         if(nHours == 1) then&lt;br /&gt;
            sTime = sTime .. &amp;quot;hour &amp;quot;&lt;br /&gt;
         else&lt;br /&gt;
            sTime = sTime .. &amp;quot;hours &amp;quot;&lt;br /&gt;
         end         &lt;br /&gt;
      end&lt;br /&gt;
      if(nMins &amp;gt; 0) then&lt;br /&gt;
         sTime = sTime .. nMins&lt;br /&gt;
              if(nMins == 1) then&lt;br /&gt;
            sTime = sTime .. &amp;quot;minute &amp;quot;&lt;br /&gt;
         else&lt;br /&gt;
            sTime = sTime .. &amp;quot;minutes &amp;quot;&lt;br /&gt;
         end         &lt;br /&gt;
      end&lt;br /&gt;
      local nSecs = math.floor(nSeconds - nHours*3600 - nMins *60) &lt;br /&gt;
      if(nSecs &amp;gt; 0) then &lt;br /&gt;
         sTime = sTime .. nSecs&lt;br /&gt;
              if(nSecs == 1) then&lt;br /&gt;
            sTime = sTime .. &amp;quot;second&amp;quot;&lt;br /&gt;
         else&lt;br /&gt;
            sTime = sTime .. &amp;quot;seconds&amp;quot;&lt;br /&gt;
         end&lt;br /&gt;
      end&lt;br /&gt;
      return sTime &lt;br /&gt;
   end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function update(device, id, power, energy, index)&lt;br /&gt;
   if (index &amp;lt; 4) then&lt;br /&gt;
      commandArray[index] = {[&amp;#039;UpdateDevice&amp;#039;] = id .. &amp;quot;|0|&amp;quot; .. power .. &amp;quot;;&amp;quot; .. energy}&lt;br /&gt;
   else&lt;br /&gt;
      commandArray[index] = {[&amp;#039;UpdateDevice&amp;#039;] = id .. &amp;quot;|0|&amp;quot; .. energy}&lt;br /&gt;
   end&lt;br /&gt;
   return&lt;br /&gt;
end   &lt;br /&gt;
&lt;br /&gt;
commandArray = {}&lt;br /&gt;
&lt;br /&gt;
local voltage = 243&lt;br /&gt;
local houseid = 300&lt;br /&gt;
local heatpumpid = 301&lt;br /&gt;
local solarid = 298&lt;br /&gt;
local usedid = 306&lt;br /&gt;
local generatedid = 307 &lt;br /&gt;
&lt;br /&gt;
if devicechanged[&amp;#039;Owl&amp;#039;] then&lt;br /&gt;
   owl = otherdevices_svalues[&amp;#039;Owl&amp;#039;]&lt;br /&gt;
   print(&amp;#039;Owl : &amp;#039;..owl)&lt;br /&gt;
   words = {}&lt;br /&gt;
   for w in string.gmatch(owl, &amp;quot;%d+%.?%d*&amp;quot;) do&lt;br /&gt;
      words[#words + 1] = w&lt;br /&gt;
   end&lt;br /&gt;
   nhousePower, houseEnergy = string.match(otherdevices_svalues[&amp;#039;Household&amp;#039;], &amp;quot;(%d+%.*%d*);(%d+%.*%d*)&amp;quot;)&lt;br /&gt;
   nheatpumpPower, heatpumpEnergy = string.match(otherdevices_svalues[&amp;#039;Heat Pump&amp;#039;], &amp;quot;(%d+%.*%d*);(%d+%.*%d*)&amp;quot;)&lt;br /&gt;
   nsolarPower, solarEnergy = string.match(otherdevices_svalues[&amp;#039;Solar&amp;#039;], &amp;quot;(%d+%.*%d*);(%d+%.*%d*)&amp;quot;)&lt;br /&gt;
   usedEnergy = string.match(otherdevices_svalues[&amp;#039;Imported&amp;#039;], &amp;quot;%d+%.*%d*&amp;quot;)&lt;br /&gt;
   generatedEnergy= string.match(otherdevices_svalues[&amp;#039;Exported&amp;#039;], &amp;quot;%d+%.*%d*&amp;quot;)&lt;br /&gt;
   interval = timedifference(otherdevices_lastupdate[&amp;#039;Owl Switch&amp;#039;])&lt;br /&gt;
-- convert internal in seconds into hours&lt;br /&gt;
   interval = interval / 3600&lt;br /&gt;
-- calculate power (voltage * current) and cumulative energy (current energy + power * time)&lt;br /&gt;
-- for each monitored line &lt;br /&gt;
   housePower = voltage * tonumber(words[1])&lt;br /&gt;
   houseEnergy = tonumber(houseEnergy) + (housePower * interval)&lt;br /&gt;
   heatpumpPower = voltage * tonumber(words[2])&lt;br /&gt;
   heatpumpEnergy = tonumber(heatpumpEnergy) + (heatpumpPower * interval)&lt;br /&gt;
   solarPower = voltage * tonumber(words[3]) &lt;br /&gt;
   solarEnergy = tonumber(solarEnergy) + (solarPower * interval)&lt;br /&gt;
   currentPower = heatpumpPower + housePower - solarPower&lt;br /&gt;
   if (currentPower &amp;gt; 0) then&lt;br /&gt;
      usedEnergy = tonumber(usedEnergy) + (interval * currentPower)&lt;br /&gt;
   else&lt;br /&gt;
      generatedEnergy = tonumber(generatedEnergy) - ( interval * currentPower) &lt;br /&gt;
   end&lt;br /&gt;
-- Turn on a dummy switch so I know when power was last recorded&lt;br /&gt;
   commandArray[&amp;#039;Owl Switch&amp;#039;] = &amp;#039;On&amp;#039;&lt;br /&gt;
-- Single call to commandArray for Household only&lt;br /&gt;
   update(&amp;quot;Household&amp;quot;, houseid, housePower, houseEnergy, 1)&lt;br /&gt;
-- Heat Pump&lt;br /&gt;
   update(&amp;quot;Heat Pump&amp;quot;, heatpumpid, heatpumpPower, heatpumpEnergy, 2)&lt;br /&gt;
-- Solar only update when the sun is out means the device shows as red in Domoticz overnight, but silly to keep sending the same value back&lt;br /&gt;
   if(solarPower~=0) then&lt;br /&gt;
      update(&amp;quot;Solar&amp;quot;, solarid, solarPower, solarEnergy, 3)&lt;br /&gt;
   end&lt;br /&gt;
-- Only update import or export&lt;br /&gt;
   if (currentPower &amp;gt; 0) then&lt;br /&gt;
      update(&amp;quot;Imported&amp;quot;, usedid, 0, usedEnergy, 4)&lt;br /&gt;
   else&lt;br /&gt;
      update(&amp;quot;Exported&amp;quot;, generatedid, 0, generatedEnergy, 4)&lt;br /&gt;
   end&lt;br /&gt;
-- Power Cut Bit&lt;br /&gt;
   PowerCut = tonumber(uservariables[&amp;quot;PowerCut&amp;quot;])&lt;br /&gt;
   if(PowerCut == 0)then&lt;br /&gt;
      if(housePower &amp;lt; 10)then&lt;br /&gt;
         commandArray[&amp;#039;Variable:PowerCut&amp;#039;] = &amp;#039;1&amp;#039;&lt;br /&gt;
         os.execute(&amp;#039;/home/pi/telegram/scripts/generic/telegram.sh msg My_Name &amp;quot;Household Power Off&amp;quot;&amp;#039;)&lt;br /&gt;
         print(&amp;quot;Household Power Off&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
   else&lt;br /&gt;
      if(housePower &amp;gt; 10)then&lt;br /&gt;
         interval = timedifference(uservariables_lastupdate[&amp;#039;PowerCut&amp;#039;])&lt;br /&gt;
         os.execute(&amp;#039;/home/pi/telegram/scripts/generic/telegram.sh msg My_Name &amp;quot;Household Power Back On - after &amp;#039; .. timeCount(interval) .. &amp;#039;&amp;quot;&amp;#039;)&lt;br /&gt;
         print(&amp;quot;Household Power Back On - after &amp;quot; .. timeCount(interval))&lt;br /&gt;
         commandArray[&amp;#039;Variable:PowerCut&amp;#039;] = &amp;#039;0&amp;#039;&lt;br /&gt;
      end&lt;br /&gt;
   end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return commandArray&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Lua]]&lt;/div&gt;</summary>
		<author><name>ThinkPad</name></author>
	</entry>
</feed>