Page 1 of 1

Watercosts

Posted: Friday 20 December 2019 17:56
by remko2000
I've a RFX-meter for my waterconsumption and a P1meter. I want to have for both the dailycosts in domoticx. I've downloaded a script and made some adjustments (water was first gas). The cost of my P1-meter (kwh) works well but the watercosts don't. I think the problem is that my watermeter is a RFX-meter, the script seems to work ponly with a custom sensor. I don't have a clue how I have to change this into the script. Is there someone who knows ho to do this?

Code: Select all

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

local scriptVar = "dailyEnergyCost"

return  {
            on = { timer = { "every 5 minutes" },           -- using 6 minutes because Stroom and Water 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("Stroom") -- P1 device or comment this line
        local water = dz.devices("Water") -- Water meter or comment this line
        
        -- outPut Devices
        local electricityCost = dz.devices("Stroomkosten") -- define this virtual sensor as Custom sensor or comment this line when not used
        local waterCost = dz.devices("Waterkosten")   -- 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 waterFixedMonth = 0.01 
        --      ********************************************************************** 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.waterFixedDay  = (waterFixedMonth 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 makeTodaysWaterCosts()
            local waterTodayCost
            if waterCost then
                waterTodaysCost = dz.data.energyCosts.waterFixedDay * 10000
                waterTodaysCost = waterTodaysCost + water.counterToday * dz.data.energyCosts.CostWater
            end
           return dz.utils.round(waterTodaysCost / 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( waterCost, makeTodaysWaterCosts())
        else
            makeCostTable(item.json)
        end
    end
}
My log gives:
An error occurred when calling event handler scriptkosten
Error: dzVents: Error: (2.4.23) ...i/domoticz/scripts/dzVents/generated_scripts/kosten3.lua:85: attempt to perform arithmetic on field 'waterFixedDay' (a nil value)

Re: Watercosts

Posted: Friday 20 December 2019 19:14
by waaren
remko2000 wrote: Friday 20 December 2019 17:56 The cost of my P1-meter (kwh) works well but the watercosts don't. I think the problem is that my watermeter is a RFX-meter, the script seems to work ponly with a custom sensor. I don't have a clue how I have to change this into the script. Is there someone who knows ho to do this?
This is the script I have running at my own production system. My watermeter is type: RFXMeter subtype: RFXMeter counter

Code: Select all

--[[
            put today's electricity and (optional) today's Gas and (optional) todays Water usage costs in custom virtual sensor
            Collect information from a P1 device and a Gas and water meter 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  =   scriptVar},

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

    execute = function(dz, item)
        --  ********************************************************************* Your changes below this line *************
        -- When change anything between these lines make sure you remove 
        -- <domoticz_dir>/scripts/dzVents/data/ __data_<scriptname.lua> before next run of this script.
        
        -- input Devices
        local electricity = dz.devices("Power") -- P1 device (required)
        local gas = dz.devices("Gas") -- Gas meter or comment this line
        local water = dz.devices("Watermeter") -- Water 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
        local waterCost = dz.devices("waterCost today")   -- define this virtual sensor as Custom sensor or comment this line when not used
        
        -- fixed Transport + contract costs per Year / Month or Day in Euro's 
        local electricityFixedMonth = 6.31    -- either electricityFixedyear, electricityFixedMonth or electricityFixedDay or comment this line 
        local gasFixedYear = 75.72            -- either gasFixedyear, gasFixedMonth or gasFixedDay or comment this line 
        local waterFixedDay = 0.2052          -- either waterFixedyear, waterFixedMonth or waterFixedDay or comment this line 
        --      ********************************************************************** 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 getDaysForYear(year)       -- Returns number of days in given or current year
              if year == nil then year = dz.time.year end
              return (year%4==0 and (year%100~=0 or year%400==0) and 366 or 365)
        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
                local daysThisMonth = getDaysForMonth()
                local daysThisYear = getDaysForYear()
                
                dz.data.energyCosts = t
                dz.data.energyCosts.electricityFixedDay = ( electricityFixedMonth and ( electricityFixedMonth / daysThisMonth )) or 
                                                          ( electricityFixedYear  and  ( electricityFixedYear / daysThisYear )) or 
                                                            electricityFixedDay
                
                dz.data.energyCosts.gasFixedDay = ( gasFixedMonth and ( gasFixedMonth / daysThisMonth )) or 
                                                  ( gasFixedYear  and  ( gasFixedYear / daysThisYear )) or 
                                                    gasFixedDay
                
                dz.data.energyCosts.waterFixedDay = ( waterFixedMonth and ( waterFixedMonth / daysThisMonth )) or 
                                                    ( waterFixedYear  and  ( waterFixedYear / daysThisYear )) or 
                                                      waterFixedDay
                
                
                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 makeTodaysWaterCosts()
            local waterTodayCost 
            if waterCost then
                local waterTodaysCost = dz.data.energyCosts.waterFixedDay 
                waterTodaysCost = waterTodaysCost + ( water.counterToday * dz.data.energyCosts.CostWater / ( dz.data.energyCosts.DividerWater * 100000))
                return dz.utils.round(waterTodaysCost, 2)
            end
        end
        
        local function makeTodaysGasCosts()
            local gasTodayCost
            if gasCost then
                gasTodaysCost = dz.data.energyCosts.gasFixedDay * 10000
                gasTodaysCost = gasTodaysCost + gas.counterToday * dz.data.energyCosts.CostGas
                return dz.utils.round(gasTodaysCost / 10000, 2)
            end
        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
                return dz.utils.round(electricityTodaysCost / 10000,2) 
            end
        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())
            updateCustomSensor( waterCost, makeTodaysWaterCosts())
        else
            makeCostTable(item.json)
        end
    end
}
costs.png
costs.png (105.03 KiB) Viewed 543 times

Re: Watercosts

Posted: Sunday 22 December 2019 10:49
by remko2000
Thx for your reply. I tried your script but get some errors in my log:

Code: Select all

2019-12-22 10:45:00.744 Error: dzVents: Error: (2.4.23) dailyEnergyCost: There is no device with that name or id: Waterverbruik
2019-12-22 10:45:00.746 Error: dzVents: Error: (2.4.23) dailyEnergyCost: An error occurred when calling event handler kosten4
2019-12-22 10:45:00.746 Error: dzVents: Error: (2.4.23) dailyEnergyCost: ...i/domoticz/scripts/dzVents/generated_scripts/kosten4.lua:110: attempt to index upvalue 'water' (a nil value)
My ID 'Waterverbruik' is correct and I use this name also in your script so I don't understand this error.

I use a watersensor of the type RFXmeter - RFX meter Counter (so no water but counter).

Re: Watercosts

Posted: Sunday 22 December 2019 12:54
by waaren
remko2000 wrote: Sunday 22 December 2019 10:49 I tried your script but get some errors in my log:
If you are sure about the name and that the device is active ; please change line 28 from

Code: Select all

local water = dz.devices("Waterverbruik") -- Water meter or comment this line
to

Code: Select all

local water = dz.devices(xxx) -- Change xxx to the idx of of your active watermeter (without quotes) 
water.dump()