Calculate daily energy cost Topic is solved

Moderator: leecollings

Piacco
Posts: 69
Joined: Friday 14 November 2014 9:33
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Calculate daily energy cost

Post by Piacco »

Hello,

I'am want to calculate the total daily energycost.

But i'am struggling with the P1 data, i can read the total daily used energy with the following code

Code: Select all

local todayKwh= dz.devices('Power').counterToday  -- Used energy today 
But how can i read the counter Return today the code below is not working

Code: Select all

local ReturntodayKwh= dz.devices('Power').counterTodayReturn  -- Delivered energy today
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Calculate daily energy cost

Post by waaren »

Piacco wrote: Thursday 24 October 2019 22:13 How can i read the counter Return today ?
If you look at the wiki P1 subject you will find the correct attribute.
Try

Code: Select all

local ReturntodayKwh= dz.devices('Power').counterDeliveredToday
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Piacco
Posts: 69
Joined: Friday 14 November 2014 9:33
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Calculate daily energy cost

Post by Piacco »

Thanks @waaren, next time i will have a better look in the wiki :roll:
plugge

Re: Calculate daily energy cost

Post by plugge »

waaren wrote: Saturday 20 April 2019 0:37
EdwinK wrote: Wednesday 17 April 2019 10:37 Working for me too ;)

Just something else.. I have two tariffs for electricity, (High and low (11pm-07am). How can I add those, and I guess that the other settings are for transportation costs.
Working with tariffs and returning energy to the grid (solar panels) need a different approach.
Can you try below script ?

Code: Select all

--[[
            put today's electricity and / or today's Gas usage costs in custom virtual sensor
            Collect information from a P1 device and /or a Gas device
            electricity takes different tariffs and returns (from solarpanels or the likes) into account.
            
]]--

local scriptVar = "dailyEnergyCost"

return  {
            on = { timer = { "every 6 minutes" },           -- using 6 minutes because Stroom and Gas are updated very frequently
                   httpResponses = { scriptVar .. "*" },
        },

        logging = { level   =   domoticz.LOG_DEBUG,    -- change to LOG_ERROR when script executes OK
                    marker  =   sciptVar},

        data =  { energyCosts = { initial = {} }
                },

    execute = function(dz, item)
        --  ********************************************************************* Your changes below this line *************
        -- input Devices
        local electricity = dz.devices("Power") -- P1 device or comment this line
        local gas = dz.devices("Gas") -- Gas meter or comment this line
        
        -- outPut Devices
        local electricityCost = dz.devices("electricityCost today") -- define this virtual sensor as Custom sensor or comment this line when not used
        local gasCost = dz.devices("gasCost today")   -- define this virtual sensor as Custom sensor or comment this line when not used
        
        -- fixed Transport + contract costs per month in Euro's
        local electricityFixedMonth = 6.31 
        local gasFixedMonth = 6.31 
        --      ********************************************************************** No changes below this line **************

        local function getDaysForMonth(month, year)       -- Returns number of days in given or current month
            if month == nil then month = dz.time.month end
            if year == nil then year = dz.time.year end
            return os.date('*t',os.time{year=year,month=month+1,day=0}).day
        end

        local function triggerJSON(url, response, delay)
            local delay = delay or 0
            dz.openURL({    url = url,
                            method = "GET",
                            callback = response}).afterSec(delay)
        end
        
        local function getCosts(id) -- these costs should be set in domoticz settings
            if next(dz.data.energyCosts) == nil  or dz.data.energyCosts.creationTime < ( dz.time.dDate - dz.time.secondsSinceMidnight ) then
                local costURL = dz.settings['Domoticz url'] .. "/json.htm?param=getcosts&type=command&idx=" .. id
                triggerJSON(costURL, scriptVar .. "_cost")
            end
            return ( next(dz.data.energyCosts) ~= nil )
        end
        
        local function makeCostTable(t) -- (re)Create costTable if not existing yet; Refreshed at least once a day
            if next( dz.data.energyCosts ) == nil or dz.data.energyCosts.creationTime < ( dz.time.dDate - dz.time.secondsSinceMidnight ) then
                dz.data.energyCosts = t
                dz.data.energyCosts.electricityFixedDay  = (electricityFixedMonth or 0 ) / getDaysForMonth()
                dz.data.energyCosts.gasFixedDay  = (gasFixedMonth or 0 ) / getDaysForMonth()
                dz.data.energyCosts.creationTime = dz.time.dDate
                dz.data.energyCosts.humanReadableCreationTime = dz.time.raw
            end
        end
        
        local function updateCustomSensor(device, value) 
            local currentValue = device.rawData[1]
            if value ~= tonumber(currentValue) then              -- Update only needed when new value is different fom previous one 
                dz.log(device.name .. " ==>> previous value: " .. currentValue .. " ; new value " .. value,dz.LOG_DEBUG)
                device.updateCustomSensor(value) 
            end
        end
        
        local function getEnergy(id)
            local energyURL = dz.settings['Domoticz url'] .. "/json.htm?range=month&sensor=counter&type=graph" ..
                                "&actmonth=" .. dz.time.month ..
                                "&idx=" .. id
                triggerJSON(energyURL, scriptVar .. "_energy")
        end
        
        local function makeTodaysGasCosts()
            local gasTodayCost
            if gasCost then
                gasTodaysCost = dz.data.energyCosts.gasFixedDay * 10000
                gasTodaysCost = gasTodaysCost + gas.counterToday * dz.data.energyCosts.CostGas
            end
           return dz.utils.round(gasTodaysCost / 10000, 2)
        end
        
        local function makeTodaysElectricityCosts(t)
            local today
            for i, record in ipairs(t) do
                if record.d == dz.time.rawDate then
                    today = i
                end
            end
            
            local electricityTodaysCost
            if electricityCost then 
                electricityTodaysCost = dz.data.energyCosts.electricityFixedDay * 10000
                if today then 
                    electricityTodaysCost = electricityTodaysCost + t[today].v * dz.data.energyCosts.CostEnergy
                    electricityTodaysCost = electricityTodaysCost + t[today].v2 * dz.data.energyCosts.CostEnergyT2
                    electricityTodaysCost = electricityTodaysCost - t[today].r1 * dz.data.energyCosts.CostEnergyR1
                    electricityTodaysCost = electricityTodaysCost - t[today].r2 * dz.data.energyCosts.CostEnergyR2
                end
            end
           
           return dz.utils.round(electricityTodaysCost / 10000,2) 
        end
        
        local function updateCustomSensor(device, value)
            if device == nil or value == nil then
                return 
            end
            local currentValue = device.rawData[1]
            if value ~= tonumber(currentValue) then              -- Update only needed when new value is different fom previous one 
                dz.log(device.name .. " ==>> previous value: " .. currentValue .. " ; new value " .. value,dz.LOG_DEBUG)
                device.updateCustomSensor(value) 
            end
        end
        
        if not ( item.isHTTPResponse ) then
            if not ( getCosts(electricity.id) ) then 
                -- logWrite("No or outdated costs. Next time the costs will be there")
                return 
            end 
            -- logWrite("-- costs are there; get energy data")
            getEnergy(electricity.id)
        elseif item.trigger == ( scriptVar .. "_energy" ) then
            updateCustomSensor( electricityCost, makeTodaysElectricityCosts(item.json.result))
            updateCustomSensor( gasCost, makeTodaysGasCosts())
        else
            makeCostTable(item.json)
        end
    end
}
@waaren. Thank you for this script, it's works fine for me. I am new to Domoticz, still learning.
I have added a user variable to gather the accumulated costs for gas and electricity for each day during a contract period (i.e., a year).
However, I could not find the moment in the script where the final daily costs are ready (to be intercepted by me, to be added to my user variable) and a new counter for the day starts. I know that it is around midnight and involves the fixed costs for the day. But where in your script could I intercept the final daily costs? (If I setup a test based on a guess, I'll have to wait a day to see if it works. :-/ )
Thank you for any help!
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Calculate daily energy cost

Post by waaren »

plugge wrote: Friday 05 June 2020 13:27Where in your script could I intercept the final daily costs?
If you retrieve the values from the energyCost and gasCost devices just below line 135

Code: Select all

makeCostTable(item.json)
You should find the final daily costs. This part of the script will execute shortly after midnight so the costs are from yesterday
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
plugge

Re: Calculate daily energy cost

Post by plugge »

Thank you waaren!
plugge

Re: Calculate daily energy cost

Post by plugge »

waaren wrote: Tuesday 16 April 2019 21:04 the method text is not available for device type custom sensor. You need another function to do that. Try this:

Code: Select all

return {
    on = { timer   = { "every 6 minutes" }},                 -- using 6 minutes because Stroom and Gas are updated very frequently

      logging =   {   level   =   domoticz.LOG_DEBUG,    -- Remove -- on these two lines if you want debug logging
                      marker  =   "EnergyCost" },    

    execute = function(dz)
        -- Devices
        local todayKwh      = dz.devices("Power").counterToday
        local todayM3       = dz.devices("Gas").counterToday
        local energyCost    = dz.devices("energyCost today") -- define this virtual sensor as Custom sensor
        local gasCost       = dz.devices("gasCost today")   -- define this virtual sensor as Custom sensor
        
        -- Price in Euro's / Kwh - M3
        local kwhPrice      = 0.20
        local gasM3Price    = 0.62
        local kwHFixedDay   = 6.99 / 31
        local m3FixedDay    = 6.99 / 31

        -- calculations
        local kwhValue  = dz.utils.round( (kwhPrice * todayKwh + kwHFixedDay),2)   -- rounded to two decimals
        local m3Value   = dz.utils.round( (gasM3Price * todayM3 + m3FixedDay),2)
        
        local function updateCustomSensor(device, value)
            local currentValue = device.rawData[1]
            if value ~= tonumber(currentValue) then              -- Update only needed when new value is different fom previous one 
                dz.log(device.name .. " ==>> previous value: " .. currentValue .. " ; new value " .. value,dz.LOG_DEBUG)
                device.updateCustomSensor(value) 
            end
        end
        
        -- call function
        updateCustomSensor(energyCost, kwhValue) 
        updateCustomSensor(gasCost, m3Value) 
        
    end
}
Hi,
In the above code, the following function - updateCustomSensor(device, value) - turns out to be always true, even when currentValue and value are equal:

Code: Select all

        local function updateCustomSensor(device, value)
            if device == nil or value == nil then
                return 
            end
            local currentValue = device.rawData[1]
            if value ~= tonumber(currentValue) then              -- Update only needed when new value is different fom previous one 
                dz.log(device.name .. " ==>> previous value: " .. currentValue .. " ; new value " .. value,dz.LOG_DEBUG)
                device.updateCustomSensor(value) 
            end
        end
See my log snippet:

Code: Select all

2020-06-26 15:00:00.462 Status: dzVents: Info: ------ Start internal script: DailyEnergyCosts: HTTPResponse: "dailyEnergyCosts_energy"
2020-06-26 15:00:00.488 Status: dzVents: Info: Power costs today ==>> previous value: -1.01 ; new value -1.01
2020-06-26 15:00:00.488 Status: dzVents: Info: Gas costs today ==>> previous value: 1.04 ; new value 1.04
2020-06-26 15:00:00.488 Status: dzVents: Info: Energy costs today ==>> previous value: 0.03 ; new value 0.03
2020-06-26 15:00:00.490 Status: dzVents: Info: ------ Finished DailyEnergyCosts
This should never enter the log since both values are the same.
Any idea what could be wrong?
TIA
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Calculate daily energy cost

Post by waaren »

plugge wrote: Friday 26 June 2020 15:13 ..... This should never enter the log since both values are the same.
Any idea what could be wrong?
TIA
Maybe value is not a numbertype in

Code: Select all

if value ~= tonumber(currentValue) then 
Try changing this in

Code: Select all

if tonumber(value) ~= tonumber(currentValue) then 
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
plugge

Re: Calculate daily energy cost

Post by plugge »

waaren wrote: Friday 26 June 2020 16:20
plugge wrote: Friday 26 June 2020 15:13 ..... This should never enter the log since both values are the same.
Any idea what could be wrong?
TIA
Maybe value is not a numbertype in

Code: Select all

if value ~= tonumber(currentValue) then 
Try changing this in

Code: Select all

if tonumber(value) ~= tonumber(currentValue) then 
Hi waaren, that was my first thought, but that didn't make any difference. The rule keeps firing with equal tonumber() values, but shouldn't:

Code: Select all

2020-06-26 16:20:00.086 Status: EventSystem: Script event triggered: D:\Program Files (x86)\Domoticz\dzVents\runtime\dzVents.lua
2020-06-26 16:20:00.200 Status: dzVents: Info: ------ Start internal script: DailyEnergyCosts: HTTPResponse: "dailyEnergyCosts_energy"
2020-06-26 16:20:00.226 Status: dzVents: Info: Energy costs today ==>> previous value: -0.18 ; new value -0.18
2020-06-26 16:20:00.227 Status: dzVents: Info: ------ Finished DailyEnergyCosts
plugge

Re: Calculate daily energy cost

Post by plugge »

Maybe lua doesn't like the following function call?

Code: Select all

updateCustomSensor( energyCost, gascosts + powercosts)
Changed it by moving the addition to a local

Code: Select all

local sum = tonumber(gascosts) + tonumber(powercosts)
updateCustomSensor( energyCost, sum)
 
That seems to do the trick.
Still puzzled about the behavior though.
plugge

Re: Calculate daily energy cost

Post by plugge »

plugge wrote: Friday 26 June 2020 17:18 That seems to do the trick.
Still puzzled about the behavior though.
No, it doesn't. The rule still fires with (seemingly) equal values:

Code: Select all

2020-06-26 17:30:00.673 Status: dzVents: Info: Energy costs today ==>> previous value: -0.38 ; new value -0.38
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Calculate daily energy cost

Post by waaren »

plugge wrote: Friday 26 June 2020 17:43 No, it doesn't. The rule still fires with (seemingly) equal values:
what about ?

Code: Select all

if dz.utils.round(tonumber(value),2) ~= dz.utils.round(tonumber(currentValue),2) then 
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
plugge

Re: Calculate daily energy cost

Post by plugge »

Nope.

Code: Select all

2020-06-26 18:45:00.230 Status: dzVents: Info: Energy costs today ==>> previous value: -0.42 ; new value -0.43
2020-06-26 18:50:00.541 Status: dzVents: Info: Energy costs today ==>> previous value: -0.43 ; new value -0.43
2020-06-26 18:55:00.477 Status: dzVents: Info: Energy costs today ==>> previous value: -0.43 ; new value -0.43
2020-06-26 19:00:01.204 Status: dzVents: Info: Energy costs today ==>> previous value: -0.43 ; new value -0.41
Interestingly it only occurs with the custom sensor that I added. Same type as the custom gas and power sensors. But apparently something is different with the value stored.
Now trying to see what happens when:

Code: Select all

local currentValue = dz.utils.round(tonumber(device.rawData[1],2)
plugge

Re: Calculate daily energy cost

Post by plugge »

plugge wrote: Friday 26 June 2020 19:15 Now trying to see what happens when:

Code: Select all

local currentValue = dz.utils.round(tonumber(device.rawData[1],2)
That did the trick!
No more equal value entries in the log, so the rule works.
Apparently the print() in the log truncates values?
Thanx
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest