Virtual meter

From Domoticz
Revision as of 14:13, 17 May 2021 by Walter vl (talk | contribs) (→‎Create virtual meter)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Smart meters only measure net electricity consumption/production, i.e. Electricity consumption - Electricity production. This script subtracts electricity production from smart meter readings to get electricity consumption. It's triggered each time the smart meter or PV meter update.

Create virtual meter

  1. Create dummy hardware and device
    1. If no Dummy Hardware already available, go to Setup -> Hardware. Else go to step 3
      1. Name: anything, e.g. "Virtual Devices" (this name is only used internally)
      2. Type: "Dummy (does nothing, use for virtual switches only)"
    2. Click on 'Add'
    3. Click on 'Create Virtual Sensors' from the table of hardware above
      1. Name: anything, e.g. "Power Consumption" (this name is displayed on the dashboard etc.)
      2. Sensor type: "Electric (Instant+Counter)"
    4. Click 'Ok'
  2. Get name/id of relevant sensors
    1. Note down the name of your smart meter and solar meter devices (not hardware)
    2. Note the name and ID of your virtual sensor
  3. Update and copy the script below
    1. Update meter / sensor names
    2. Go to Setup -> More Options -> Events
    3. Enter name (e.g. PowerConsumption), Select 'Lua' and 'Device'
    4. Toggle event active, save
  4. Update utility/dashboard accordingly

Lua script

-- Power consumption device script - SunnyBoy 20180523
--
-- Smart meters only measure net electricity consumption/production, i.e. 
-- Electricity consumption - Electricity production. This script subtracts 
-- electricity production from smart meter readings to get electricity 
-- consumption. It's triggered each time the smart meter or PV meter update.
--
-- 1. Create dummy hardware and device
-- 1.1 Go to Setup -> Hardware 
--     Name: anything, e.g. "Ele_Consumption" (this name is only used internally)
--     Type: "Dummy (does nothing, use for virtual switches only)"
-- 1.2 Click on 'Add'
-- 1.3 Click on 'Create Virtual Sensors' from the table of hardware above
--     Name: anything, e.g. "Power Consumption" (this name is displayed on the dashboard etc.)
--     Sensor type: "Electric (Instant+Counter)"
-- 1.4 Click 'Ok'
-- 2. Get name/id of relevant sensors
-- 2.1. Note down the name of your smart meter and solar meter devices (not hardware)
-- 2.2. Note the name and ID of your virtual sensor
-- 3. Update and copy the script below
-- 3.1. Update meter / sensor names
-- 3.2. Go to Setup -> More Options -> Events
-- 3.3. Enter name (e.g. PowerConsumption), Select 'Lua' and 'Device'
-- 3.4. Toggle event active, save
-- 4. Update utility/dashboard accordingly

commandArray = {}
debug = false

-- for debugging, use this file
if (debug) then
    file = io.open("/home/pi/lua_test.log", "a") -- append
end

-- Update these lines before use
smartmeter = "Power (net)" -- name of smart meter device
solarmeter = "Solar Power" -- name of solar meter device
dummymeter = "Power Consumption" -- name of virtual sensor
dummymeter_id = 20 -- ID of virtual sensor
dummymeter_trigger = solarmeter -- name of the meter to trigger the dummy meter update. Use the slowest meter here: if your smart meter updates every 10 sec and PV every 100 sec, you get 9 values using potentially outdated PV data. In my case cloudy days gave negative consumption because of this.

-- debug to check what devices are named (but better use 'Show current states' in
-- online editor)
if (debug) then
    file:write('other devices states:\n')
    for i, v in pairs(otherdevices) do file:write(i, v) end
    file:write("\n")
    file:write('other devices svalues:\n')
    for i, v in pairs(otherdevices_svalues) do file:write(i, v) end
    file:write("\n")
end

-- loop through all the changed devices, only update during day if solar meter
-- is triggered, or during the night if smart meter is triggered.
for deviceName,deviceValue in pairs(devicechanged) do
    if (debug) then
        file:write("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'\n");
    end
    
    -- Looks like: Device based event fired on 'Power (net)', value '2058750;1175597;790812;1911744;251;0'
    -- Syntax: USAGE1;USAGE2;RETURN1;RETURN2;CONS;PROD https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Electricity_P1_smart_meter
    -- Counter: T1: 2058.750, T2: 1175.671
    -- Counter Return: R1: 790.812, R2: 1911.744
    -- Or: Device based event fired on 'Solar Power', value '0.000;3755165.000'
    -- Counter: 3755.165
    -- Time of script consumption counter: 2058.750 + 1175.671 + 3755.165 - 790.812 - 1911.744
    if (deviceName == solarmeter and timeofday['Daytime']) or (deviceName == smartmeter and timeofday['Nighttime']) then
        -- Smart meter: Match six integers separated by semicolum
        -- first four are energy meters, last two are power meters?
        smart_e1, smart_e2, smart_e3, smart_e4, smart_p1, smart_p2 = otherdevices_svalues[smartmeter]:match("([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);([^;]+)")
        -- Solar meter power;counter: 0.000;3755165.000
        solar_p, solar_e = otherdevices_svalues[solarmeter]:match("([^;]+);([^;]+)")
        
        -- Calculate power consumption and update dummy device. Consumption is 
        -- always positive, so we add our solar power to the smart meter power
        -- if solar generates 1kW, smart meter shows -0.5kW, real consumption is 0.5kW (=solar - return)
        -- if solar generates 1kW, smart meter shows 0.5kW, real consumption is 1.5kW (=solar + consumption)
        consumption_p = smart_p1 + solar_p - smart_p2
        consumption_e = smart_e1 + smart_e2 + solar_e - smart_e3 - smart_e4
        
        -- Populate commandArray with update command
        commandArray[1] = {['UpdateDevice'] = dummymeter_id .. "|0|" .. consumption_p .. ";" .. consumption_e}
        if (debug) then
            file:write("Update device".. dummymeter_id .. "|0|" .. consumption_p .. ";" .. consumption_e .. "\n");
        end
    end
end

if (debug) then
    file:close()
end

return commandArray

References