Background
With new legislation in The Netherlands, starting from 2020, it is likely that solar panel owners in the Netherlands will receive less money for energy that they feed into the electricity grid then what they pay for energy that they retrieve from that same electricity grid.
Currently, solar panel owners can use the electricity grid as one big solar battery with a 100% efficiency. The value of the ‘generate’ meter will be deducted from the ‘usage’ meter, meaning that both meters are considered to be equal in value per kWh. However, the biggest portion of the kWh price is (energy) taxes, but also partially usage of the electricity grid. Considering the value of generated and used electricity equal in value can be considered as subsidies. Unfortunately for solar panel owners the Dutch government wants to use those subsidies to develop other opportunities for clean energy, since solar energy is considered to be mature by now.
Since this forum is not meant for political topics, but for technical solutions, let’s move on to counter measures, how to optimize our systems for maximum financial / electrical profit. With a solar system it is inevitable that generation and usage of electricity is not balanced. A battery, like for instance the Tesla Powerwall, will be a good solution to store the surplus of generated energy locally ‘behind the meter’. There where the solar panel owner is in charge.
The question is, what size battery should I buy? It is not recommended to be too small, it will be full and empty much too fast. Not too big either, it doesn’t make sense to fill the battery on a sunny summer day to the top, use it for your nightly consumption and find the battery the next morning still half full, leaving only half the battery available for charging on day 2. Ideally the battery tips the ‘full’ and the ‘empty’ point each day without overshoot in both directions.
Technical
Well, Domoticz can be used for making the right choice. With 3 virtual devices the presence of a solar battery behind the meter can be simulated. It is up to the user to tweak the capacity of the virtual battery to find the sweet spot for max use of the battery through the year. In my case I started with a 4000 Wh virtual battery. Already in the spring I saw that the battery reached ‘full’ and ‘empty’ point on a lot of days in a row. I therefore increased the battery (for free

The script doesn’t take into consideration the cost/reward for a bigger/small battery. The meter logs can be exported to Excel for more precise financial calculation.
Update:
02-04-2021: DzVents version of the script, with additional functionality, can be found on GitHub!
19-04-2021: Version 0.2 released with better registration of all elements that impact maximum efficiency of solar battery usage.
DEPRECIATED INFORMATION ABOUT THE OLD LUA SCRIPT CAN BE FOUND HERE BELOW
Basis for the solar battery script:
The script expects a Domoticz kWh meter, like the P1 smart meter, that outputs a total electricity value, the Wh meter value becomes higher when energy consumed and lower when energy is fed back into the electricity grid.
Code: Select all
--Script_time_solar_battery.lua
--Time based Script to simulate a battery to store harvested solar energy at times it is not consumed directly by the appliances in the house/office/factory
--3 Devices will be calculated:
-- (1): Virtual solar battery
-- (2): Energy counter to see how much energy is consumed from the solar battery. Are you using your battery capacity every day,
-- not only for charging, but also for emptying. At big energy consumption, the battery can be used 'multiple' times in a day,
-- when the energy harvesting < temporary big energy consumption
-- (3): Energy counter to see how much energy is lost with the given battery capacity. This is measured both for a full battery while still
-- harvesting energy as for an empty battery while there is energy consumption (optional, see settings variable)
--Manually create and/or define below (newly created virtual) devices and 'User Variables' by user given names
local electricity_meter = 'Electricity' -- Existing P1 Electricity device name in 'Utility'
--To be created virtual devices in the hardware section of Domoticz:
local solar_battery = 'Virtual Solar Battery' -- (1) Custom Sensor name for the 'Virtual Solar Battery'
local solar_battery_idx = 189
local battery_use = 'Solar Battery Usage' -- (2) RFXMeter counter name for the 'Solar Battery Usage'
local battery_use_idx = 195
local lost_energy = 'Lost Solar Energy' -- (3) RFXMeter counter name for the 'Lost Solar Energy'
local lost_energy_idx = 194
--User Variables:
local battery_capacitylevel = 'SolarBatteryCapacity' -- User Variable name for the 'Solar Battery Capacity'. Type 'String'. Value in Wh (4kWh battery = '4000')
local total_electricity = 'TotalElectricity' -- User Variable to store the total sum of P1 electricity meter. Type 'String'. Value initially must be '0'
--Settings variable for the 'Lost Solar Energy' meter to include/exclude energy consumption while the battery is already empty:
local empty_battery = 1 -- 1 = Include (in other words, with either more solar panels to fill the battery or a
-- bigger capacity, energy consumption from the grid could have been avoided)
-- 0 = Exclude (in other words, the meter shows in the monthly graph exactly how big the
-- battery should have been to catch all generated solar energy)
--Define variables, used in this script. Don't change!!!
local battery_capacity
local old_total_electricity
local new_total_electricity
local electricity_consumption
local old_battery_value
local new_battery_value
local lost_energy_value
local old_lost_energy_value
local new_lost_energy_value
local battery_usage
local old_battery_usage
local new_battery_usage
commandArray = {}
battery_capacity = tonumber (uservariables[battery_capacitylevel])
if tonumber (uservariables[battery_capacitylevel]) == nil then
battery_capacity = 2000
print ("Battery capacity in User Variables was not a number. Capacity will be set to 2000Wh")
commandArray ['Variable:'.. battery_capacitylevel] = tostring(battery_capacity)
else
battery_capacity = tonumber (uservariables[battery_capacitylevel])
end
sPlusT1, sPlusT2, sMinT1, sMinT2 = otherdevices_svalues[electricity_meter]:match("([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);([^;]+)")
sPlusT1 = tonumber(sPlusT1); -- energy usage, low tarrif
sPlusT2 = tonumber(sPlusT2); -- energy usage, high tarrif
sMinT1 = tonumber(sMinT1); -- energy generated, low tarrif
sMinT2 = tonumber(sMinT2); -- energy generated, high tarrif
--print (sPlusT1 .." " .. sPlusT2 .." " .. sMinT1 .." " .. sMinT2)
--Calculate the new total meter value in Wh (both incoming meters minus both outgoing meters)
new_total_electricity = (sPlusT1 + sPlusT2) - (sMinT1 + sMinT2)
--print ("new electricity level is " .. new_total_electricity)
-- Download the previous total meter value from the variable to start the comparison
if tonumber (uservariables[total_electricity]) == nil then
old_total_electricity = new_total_electricity
print (total_electricity .." in User Variables was not a number. Value will be filled with current electricity meter sum")
commandArray ['Variable:'.. total_electricity] = tostring(new_total_electricity)
else
old_total_electricity = tonumber (uservariables[total_electricity])
end
--print ("old electricity level is " .. old_total_electricity)
--Check the energy usage since last update. A positive number means electricity usage, a negative number means electricity generated
electricity_consumption = (new_total_electricity - old_total_electricity)
--print ("consumption of electricity is " .. electricity_consumption .." Wh")
--Write the new energy value to the variable
commandArray ['Variable:'.. total_electricity] = tostring(new_total_electricity)
--print ("variable TotalElectricity updated to "..tostring(new_total_electricity))
--Check if there is a valid value for the virtual solar battery level, if not (like after inital start of the virtual sensor) create a '0'
if tonumber(otherdevices_svalues[solar_battery]) == nil then
old_battery_value = 0
print ("old battery value was NIL")
else
--Download the previous value of the virtual solar battery
old_battery_value = tonumber(otherdevices_svalues[solar_battery])*1000
end
--Calculate the new battery value by subtracting the electricity consumption from the previous battery value.
--When consumption is positive, it therefore depletes the battery. If the energy consumption is negative, it means that the battery will be charged.
new_battery_value = old_battery_value - electricity_consumption
--print ('new battery level is old battery level of '.. old_battery_value .." Wh minus electricity consumption of ".. electricity_consumption.. " Wh = ".. new_battery_value .." Wh")
--Battery can not be further depleted than 'empty' and therefore not < 0 Wh
if new_battery_value > 0 then
--Check if the new battery value will not be more than it's capacity
if new_battery_value <= battery_capacity then
--print ("Battery value updated to " .. new_battery_value .." Wh")
-- Check if the new battery value will be higher than the battery capacity
elseif new_battery_value > battery_capacity then
--New battery value will be the maximum battery capacity
new_battery_value = battery_capacity
--print ("Solar battery maximum capacity of ".. battery_capacity .." Wh reached")
end
elseif new_battery_value <= 0 then
new_battery_value = 0
--print ("Solar battery is empty, energy is taken from the grid")
end
commandArray [1] = {['UpdateDevice'] = solar_battery_idx .. '|0|' .. new_battery_value/1000}
--end
-----------------------------------
--Virtual Solar Battery Use
-----------------------------------
--Count the energy used from the battery (meaning that the electricity consumption must be a positve number
if electricity_consumption > 0 then
battery_usage = old_battery_value - new_battery_value
else
battery_usage = 0
end
if tonumber(otherdevices_svalues[battery_use]) == nil then
old_battery_usage = 0
print (otherdevices_svalues[battery_use])
print ("old battery energy usage value was NIL. Either it is a first start of the script (new virtual sensor), or something is wrong")
else
--Download the previous value of the solar battery energy usage in Wh
old_battery_usage = tonumber(otherdevices_svalues[battery_use])
end
--print ("Old value of the solar battery energy usage is " .. old_battery_usage .. "Wh")
--Calculate the new value for the solar battery energy usage in Wh
new_battery_usage = old_battery_usage + battery_usage
--Virtual counter new value must be higher than the old value to prevent errors in the virtual counter calculation
--print ("New solar battery usage value of " ..new_battery_usage .. ' Wh = Old solar battery usage value of ' .. old_battery_usage .. ' Wh + battery energy usage of ' .. battery_usage .. ' Wh')
if new_battery_usage >= old_battery_usage then
commandArray [2] = {['UpdateDevice'] = battery_use_idx .. '|0|' .. new_battery_usage }
--print ("New battery usage information sent to sensor "..battery_use_idx.." with value of ".. new_battery_usage)
else
print ("Something went wrong, the new solar battery usage value of "..new_battery_usage.." is smaller than the previous value of "..old_battery_usage)
end
-----------------------------------
--Virtual Solar Energy Loss calculation
-----------------------------------
--Energy value above the battery capacity and at empty battery is 'lost' and needs to be measured to know what capacity should have been chosen
--Check if there is a valid value for the virtual lost energy level, if not (like after inital start of the virtual sensor) create a '0' value
if tonumber(otherdevices_svalues[lost_energy]) == nil then
old_lost_energy_value = 0
print ("old lost energy was NIL")
else
--Download the previous value of the virtual lost energy sensor
old_lost_energy_value = tonumber(otherdevices_svalues[lost_energy])
end
--print ("Old lost energy value is " .. old_lost_energy_value .. "Wh")
--Calculate how much energy is lost after the battery reached it's maximum capacity
lost_energy_value = old_battery_value - electricity_consumption - battery_capacity
if lost_energy_value > 0 then --meaning a negative electricity_consumption, meaning energy generated while battery was at max. capacity
--Calculate the new value for the virtual lost energy sensor
new_lost_energy_value = old_lost_energy_value + lost_energy_value
--print ("New lost energy of " ..new_lost_energy_value .. ' Wh = Old Lost Energy value of ' .. old_lost_energy_value .. ' Wh + Lost Energy value of ' .. lost_energy_value .. ' Wh')
elseif ((old_battery_value - electricity_consumption) < 0 and empty_battery == 1 ) then --meaning that there is energy consumption while battery is empty
--Calculate the new value for the virtual lost energy sensor
new_lost_energy_value = old_lost_energy_value - (old_battery_value - electricity_consumption) --battery value would have been negative, therefore subtracted ( minus x minus = plus) to come to a total lost_energy
--print ("New lost energy of " ..new_lost_energy_value .. ' Wh = Old Lost Energy value of ' .. old_lost_energy_value .. ' Wh - Lost Energy value of negative battery level ' .. (old_battery_value - electricity_consumption) .. ' Wh')
else
new_lost_energy_value = old_lost_energy_value
end
--Virtual counter new value must be higher than the old value to prevent errors in the virtual counter calculation
if new_lost_energy_value >= old_lost_energy_value then
commandArray['UpdateDevice'] = lost_energy_idx .. '|0|' .. new_lost_energy_value
else
print ("Something went wrong, the new lost energy value of "..new_lost_energy_value.." is smaller than the previous value of "..old_lost_energy_value)
end
return commandArray