Battery charging terminate before 100% is reached

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
HvdW
Posts: 612
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Battery charging terminate before 100% is reached

Post by HvdW »

Hi,
Capture.JPG
Capture.JPG (14.55 KiB) Viewed 800 times
What you see is a charging diagram for charging a battery.
On the left side charging starts, it is switched off for a while, then charging continues and on the right side you see the # of Watts drop.

I want to use this phenomenon to protect the battery from being charged to 100% (which leads to a longer battery life)

So I want to measure Watt every minute and compare the current Watt with the Watt of let's say 10 minutes before.
If the Wattage dropped by 10% compared to 10 minutes before domoticz can switch off the switch which powers the charging. (this switch maybe a relay or a Shelly or whatever)

I have mastered dzvents a little bit, however can use some assistance.


- execute every minute
- copy value_9 to value_10
- copy value_8 to value_9
- copy value_7 to value_6
- copy value_6 to value_5
- copy value_5 to value_4
- copy value_4 to value_3
- copy value_3 to value_2
- copy value_2 to value_1
- read current value to value_0
- if value_0*1.1 < value_10
dz.devices(CHARGER_SWITCH).switchOff()

I made a start.

Code: Select all

-- Script name is Batterycharger-switch

local CHARGER_SWITCH = 'ANY_SWITCH' -- switch device
local value_10 = 0 
local value_9 = 0
local value_8 = 0
local value_7 = 0
local value_6 = 0
local value_5 = 0
local value_4 = 0
local value_3 = 0
local value_2 = 0
local value_1 = 0
local value_0 = 0

return
{
    on = 
    {
        timer = 
        {
            'every minute'
        },
		-- device triggers
		devices = 
		{
			-- scripts is executed if the device that was updated matches with one of these triggers
			'Battery switch', -- device name
		},    
    },

    --LOG levell: This is the log level you want for this script. Can be domoticz.LOG_INFO, domoticz.LOG_MODULE_EXEC_INFO, domoticz.LOG_DEBUG or domoticz.LOG_ERROR
    --marker: A string that is prefixed before each log message. That way you can easily create a filter in the Domoticz log to see just these messages.

   logging =   
        {
        -- level: This is the log level you want for this script. 
        -- Can be domoticz.LOG_INFO, domoticz.LOG_MODULE_EXEC_INFO, domoticz.LOG_DEBUG or domoticz.LOG_ERROR
        -- marker: A string that is prefixed before each log message. 
        level = domoticz.LOG_INFO and domoticz.LOG_DEBUG,
        marker = "BATTERY CHARGER",
        },

    execute = function(dz)
        

}

-- end Batterycharger-switch
Bugs bug me.
roblom
Posts: 408
Joined: Wednesday 26 February 2014 15:28
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: the Netherlands
Contact:

Re: Battery charging terminate before 100% is reached

Post by roblom »

I'm not a programmer but I think you could use the historical variables function in DzEvents.

https://www.domoticz.com/wiki/DzVents:_ ... _variables
GJKNL
Posts: 41
Joined: Monday 31 October 2016 9:33
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Battery charging terminate before 100% is reached

Post by GJKNL »

For my walltablet with Dasticz I use "Automate". See: https://www.huizebruin.nl/domoticz/how- ... -domoticz/

My script:

Code: Select all

 return {
    active = true,
    on = {
        devices = {
            'Accu Wall Tablet'
        },
		
    },
    execute = function(domoticz)
        
		local accu = domoticz.devices('Accu Wall Tablet')
		local tablet = domoticz.devices('walltablet') --power plug
			
		
		if (tonumber(accu.state) < 20) 
		--if accu.state > 10
		then
		tablet.switchOn().checkFirst()
		tablet.switchOn().afterMin(5) --extra command because it is a rfx plug
		elseif
		 (tonumber(accu.state) > 80) 
		--if accu.state > 10
		then
		tablet.switchOff().checkFirst()
		tablet.switchOff().afterMin(5)
		end
		
	end
} 
HvdW
Posts: 612
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Battery charging terminate before 100% is reached

Post by HvdW »

Nice @GJKNL!
Not exactly my user case but very interesting indeed.
A powerbank doesn't transmit its battery percentage so we'll have to deal with reading the charging figures.
Bugs bug me.
plugge

Re: Battery charging terminate before 100% is reached

Post by plugge »

@HvdW
Maybe this helps to get started (not tested!):
(See: https://www.domoticz.com/wiki/DzVents:_ ... _scripting

Code: Select all

-- Script name is Batterycharger-switch

local ScriptVar = 'Charging Monitor'
-- This script requires an Electric Usage device called 'Watt monitor'

return
{
    on = 
    {
        timer = {
			'every 10 minutes',  -- change this to what you need, and adapt historicChargingLevel in data
		},

    },
	data = {
		historicChargingLevel = { history = true, maxItems = 12, maxMinutes = 120} -- 2 hours, every 10 minutes. Change it to the estimated charging time
	},

   logging =   
        {
        level = domoticz.LOG_INFO, -- change this to domoticz.LOG_DEBUG for debugging only
        marker = scriptVar,
        },

    execute = function(dz, item)
		local chargerSwitch = dz.devices('ANY_SWITCH') -- switch device
		local historicLevel = dz.data.historicChargingLevel
        historicLevel.add(dz.devices('Watt monitor').actualWatt) --or a simple dummy counter		
		local size = dz.data.historicChargingLevel.size
		if size > 1 and 
		   historicLevel.get(size) < dz.data.historicLevel.get(size-1)
		then
			dz.devices(chargerSwitch).switchOff()
			historicLevel.reset() -- remove all historic data if the charging reaches optimum level
		else
			print(scriptVar..' No drop in charging level yet')
		end
}
-- end Batterycharger-switch
HvdW
Posts: 612
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Battery charging terminate before 100% is reached

Post by HvdW »

@plugge thanks for pointing me to use persistent data.

Using a Shelly Plus 1 PM device (example) and this code your batteries will no longer be charged up to 100% which will hopefully result in a longer battery life.

The code is heavily filled with debugging info.
You can either delete those lines or set debugging to domoticz.LOG_ERROR

Some devices start with high charging rates and these rates drop after a short while.
To prevent inadverted switching off the code eliminates the first data and starts regulating after 3 minutes.

For testing purposes I started with capturing 10 minutes of data.
The code works fine with 8 minutes interval for testing.
Superfluous lines can be deleted.

The time span for comparision and sensibility can be set with this part of the code.

Code: Select all

                if domoticz.data.value_8 > 1.33 * domoticz.data.value_0 then
                    -- switch off shelly like switchoff Groene lampjes
                    domoticz.devices(CHARGER_SWITCH).switchOff()
                end
The full code:

Code: Select all

 -- Shelly get power (watt)
-- Howto at Luftdaten https://www.domoticz.com/forum/viewtopic.php?f=72&t=23406&hilit=luftdaten
-- Call Shelly with http://192.168.x.x/status
-- local Shelly = 'Shelly 21-0'

local CHARGER_SWITCH = 'Groene lampjes' -- switch device (Green lights)

return {
	active = true,
	on = {
		timer = { 'every minute' },            
		httpResponses = { 'Shelly21Retrieved' }  -- matches callback string below
	},
	
	data = {
	    counter = {initial = 0 },
	    switch_state = {initial = 'Off'},
        value_10 = { initial = 0 }, 
        value_9 = { initial = 0 },
        value_8 = { initial = 0 },
        value_7 = { initial = 0 },
        value_6 = { initial = 0 },
        value_5 = { initial = 0 },
        value_4 = { initial = 0 },
        value_3 = { initial = 0 },
        value_2 = { initial = 0 },
        value_1 = { initial = 0 },
        value_0 = { initial = 0 },
    },
    
	logging =   
        {
        -- level: This is the log level you want for this script. 
        -- Can be domoticz.LOG_INFO, domoticz.LOG_MODULE_EXEC_INFO, domoticz.LOG_DEBUG or domoticz.LOG_ERROR
        -- marker: A string that is prefixed before each log message. 
        level = domoticz.LOG_INFO and domoticz.LOG_DEBUG,
        marker = "BATTERY CHARGER",
        },
	
	execute = function(domoticz, item)

		if (item.isTimer) then
			domoticz.openURL({
				url = 'http://192.168.2.21/status',
				method = 'GET',
				callback = 'Shelly21Retrieved'
			})

		elseif (item.isHTTPResponse) then
			if (item.ok and item.isJSON) then
			    -- domoticz.utils.dumpTable(item.json)   -- dumpTable shows all values, nice for debugging
				domoticz.devices('Shelly 21').updateCustomSensor(item.json.meters[1].power)                
				-- domoticz.devices('Shelly 21').updateCustomSensor(item.json.meters[2].power)
				-- domoticz.notify('Power     ' .. item.json.meters[1].power, domoticz.PRIORITY_HIGH)     
				-- domoticz.notify('Is_valid  ' .. item.json.meters[1].is_valid, domoticz.PRIORITY_LOW) --howto display TRUE or FALSE?
				-- domoticz.log(item.json.meters[1].power, domoticz.LOG_ERROR)                         
				-- domoticz.notify('Timestamp ' .. item.json.meters[1].timestamp, domoticz.PRIORITY_LOW)  -- success
                        -- domoticz.utils.dumpTable(item.json)   -- dumpTable laat alle waarden zien, mooi voor debugging
                -- collect all input data
                local switch_state = domoticz.devices(CHARGER_SWITCH).state
                                local power_usage = item.json.meters[1].power 
                if switch_state == 'On' then
                    domoticz.data.counter = domoticz.data.counter + 1    
                elseif switch_state == 'Off' then
                    domoticz.data.counter = 0
                    domoticz.data.value_0 = 0
                    domoticz.data.value_1 = 0
                    domoticz.data.value_2 = 0
                    domoticz.data.value_3 = 0
                    domoticz.data.value_4 = 0
                    domoticz.data.value_5 = 0
                    domoticz.data.value_6 = 0
                    domoticz.data.value_7 = 0
                    domoticz.data.value_8 = 0
                    domoticz.data.value_9 = 0
                    domoticz.data.value_10 = 0
                    -- for testing there were 10 values, 6 seem to be enough
                end
                                -- Some devices start charging with high values, which drop after a few minutes
                -- That is why dat  from the first minutes are eliminated
                if switch_state == 'On' and domoticz.data.counter == 4 then
                    domoticz.log('domoticz.data.counter in de loop       : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                    domoticz.log('Groene lampjes value_4 : ' .. domoticz.data.value_4, domoticz.LOG_DEBUG)
                    domoticz.log('Groene lampjes value_3 : ' .. domoticz.data.value_3, domoticz.LOG_DEBUG)
                    domoticz.log('Groene lampjes value_2 : ' .. domoticz.data.value_2, domoticz.LOG_DEBUG)
                    domoticz.log('Groene lampjes value_1 : ' .. domoticz.data.value_1, domoticz.LOG_DEBUG)
                    domoticz.log('Groene lampjes value_0 : ' .. domoticz.data.value_0, domoticz.LOG_DEBUG)
                    -- clear the first 3 data because charging sometimes starts with a bump
                    domoticz.data.value_0 = 0
                    domoticz.data.value_1 = 0
                    domoticz.data.value_2 = 0
                    domoticz.data.value_3 = 0
                end

                domoticz.log('Groene lampjes status   : ' .. switch_state, domoticz.LOG_DEBUG)
                domoticz.log('counter        : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes Watt     : ' .. power_usage, domoticz.LOG_DEBUG)
                domoticz.data.value_10 = domoticz.data.value_9
                domoticz.data.value_9 = domoticz.data.value_8
                domoticz.data.value_8 = domoticz.data.value_7
                domoticz.data.value_7 = domoticz.data.value_6
                domoticz.data.value_6 = domoticz.data.value_5
                domoticz.data.value_5 = domoticz.data.value_4
                domoticz.data.value_4 = domoticz.data.value_3
                domoticz.data.value_3 = domoticz.data.value_2
                domoticz.data.value_2 = domoticz.data.value_1
                domoticz.data.value_1 = domoticz.data.value_0
                domoticz.data.value_0 = power_usage
                domoticz.log('domoticz.data.counter  : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_10: ' .. domoticz.data.value_10, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_9 : ' .. domoticz.data.value_9, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_8 : ' .. domoticz.data.value_8, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_7 : ' .. domoticz.data.value_7, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_6 : ' .. domoticz.data.value_6, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_5 : ' .. domoticz.data.value_5, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_4 : ' .. domoticz.data.value_4, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_3 : ' .. domoticz.data.value_3, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_2 : ' .. domoticz.data.value_2, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_1 : ' .. domoticz.data.value_1, domoticz.LOG_DEBUG)
                domoticz.log('Groene lampjes value_0 : ' .. domoticz.data.value_0, domoticz.LOG_DEBUG)

                if domoticz.data.value_8 > 1.33 * domoticz.data.value_0 then
                    -- switch off shelly like switchoff Groene lampjes
                    domoticz.devices(CHARGER_SWITCH).switchOff()
                end
			else
				-- oops
				domoticz.log('Error fetching Shelly data', domoticz.LOG_ERROR)
				domoticz.log(item.data, domoticz.LOG_ERROR)
			end
		end
	end
}
Capture.JPG
Capture.JPG (22.54 KiB) Viewed 690 times
Left line is a device that starts with a high value that drops, right line is a device that charges with a continuous level.
Last edited by HvdW on Sunday 30 October 2022 11:19, edited 2 times in total.
Bugs bug me.
HvdW
Posts: 612
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Battery charging terminate before 100% is reached

Post by HvdW »

BUMP: code updated.
Bugs bug me.
HvdW
Posts: 612
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Battery charging terminate before 100% is reached

Post by HvdW »

Hi,
Today I received the Shelly Plug S and adapted the script.
Before you begin set up a Dummy Device to act as a switch for your Shelly plug.
The command for Shelly is: http://192.168.x.x/relay/0?turn=on
Than set up another Dummy Device as CustomSensor and name the Axis label Watt.
The script itself should be self explanatory.

Code: Select all

-- Shelly (get watt)
-- Howto at Luftdaten https://www.domoticz.com/forum/viewtopic.php?f=72&t=23406&hilit=luftdaten
-- Call Shelly with http://192.168.x.x/status

local CHARGER_SWITCH = 'Plug Switch' -- switch device
local CHARGER_POWER = 'Plug Power'  -- custom sensor Watt

return {
	active = true,
	on = {
		timer = { 'every minute' },            -- every minute for testing, 10 minutes when active
		httpResponses = { 'PlugRetrieved' }  -- matches callback string below
	},
	
	data = {
	    counter = {initial = 0 },
	    switch_state = {initial = 'Off'},
        value_10 = { initial = 0 }, 
        value_9 = { initial = 0 },
        value_8 = { initial = 0 },
        value_7 = { initial = 0 },
        value_6 = { initial = 0 },
        value_5 = { initial = 0 },
        value_4 = { initial = 0 },
        value_3 = { initial = 0 },
        value_2 = { initial = 0 },
        value_1 = { initial = 0 },
        value_0 = { initial = 0 },
    },
    
	logging =   
        {
        -- level: This is the log level you want for this script. 
        -- Can be domoticz.LOG_INFO, domoticz.LOG_MODULE_EXEC_INFO, domoticz.LOG_DEBUG or domoticz.LOG_ERROR
        -- marker: A string that is prefixed before each log message. 
        level = domoticz.LOG_INFO and domoticz.LOG_DEBUG,
        marker = "BATTERY CHARGER",
        },
	
	execute = function(domoticz, item)

		if (item.isTimer) then
			domoticz.openURL({
				url = 'http://192.168.2.51/status',
				method = 'GET',
				callback = 'PlugRetrieved'
			})

		elseif (item.isHTTPResponse) then
			if (item.ok and item.isJSON) then
			    -- domoticz.utils.dumpTable(item.json)   -- dumpTable shows all values, nice for debugging
				-- collect all input data
				domoticz.log(item.json.meters[1].power, domoticz.LOG_INFO)
				domoticz.devices(CHARGER_POWER).updateCustomSensor(item.json.meters[1].power)

                local switch_state = domoticz.devices(CHARGER_SWITCH).state
                local power_usage = item.json.meters[1].power 
                if power_usage > 0 and switch_state == 'Off' then   
                    domoticz.devices(CHARGER_SWITCH).switchOn() 
                    -- bovenstaand omdat als je de plug inplugt de schakelaar in domoticz nog op off staat
                elseif switch_state == 'On' then     -- was switch_state == 'On'
                    domoticz.data.counter = domoticz.data.counter + 1    
                elseif switch_state == 'Off' then
                    domoticz.data.counter = 0
                    domoticz.data.value_0 = 0
                    domoticz.data.value_1 = 0
                    domoticz.data.value_2 = 0
                    domoticz.data.value_3 = 0
                    domoticz.data.value_4 = 0
                    domoticz.data.value_5 = 0
                    domoticz.data.value_6 = 0
                    domoticz.data.value_7 = 0
                    domoticz.data.value_8 = 0
                    domoticz.data.value_9 = 0
                    domoticz.data.value_10 = 0
                end
                if switch_state == 'On' and domoticz.data.counter == 4 then
                    domoticz.log('domoticz.data.counter in de loop       : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                    domoticz.log('Plug Power value_4 : ' .. domoticz.data.value_4, domoticz.LOG_DEBUG)
                    domoticz.log('Plug Power value_3 : ' .. domoticz.data.value_3, domoticz.LOG_DEBUG)
                    domoticz.log('Plug Power value_2 : ' .. domoticz.data.value_2, domoticz.LOG_DEBUG)
                    domoticz.log('Plug Power value_1 : ' .. domoticz.data.value_1, domoticz.LOG_DEBUG)
                    domoticz.log('Plug Power value_0 : ' .. domoticz.data.value_0, domoticz.LOG_DEBUG)
                    -- clear the first 3 data because charging sometimes starts with a bump
                    domoticz.data.value_0 = 0
                    domoticz.data.value_1 = 0
                    domoticz.data.value_2 = 0
                    domoticz.data.value_3 = 0
                end

                domoticz.log('Plug Switch status   : ' .. switch_state, domoticz.LOG_DEBUG)
                domoticz.log('counter        : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                domoticz.log('Plug Power     : ' .. power_usage, domoticz.LOG_DEBUG)
                domoticz.data.value_10 = domoticz.data.value_9
                domoticz.data.value_9 = domoticz.data.value_8
                domoticz.data.value_8 = domoticz.data.value_7
                domoticz.data.value_7 = domoticz.data.value_6
                domoticz.data.value_6 = domoticz.data.value_5
                domoticz.data.value_5 = domoticz.data.value_4
                domoticz.data.value_4 = domoticz.data.value_3
                domoticz.data.value_3 = domoticz.data.value_2
                domoticz.data.value_2 = domoticz.data.value_1
                domoticz.data.value_1 = domoticz.data.value_0
                domoticz.data.value_0 = power_usage
                domoticz.log('domoticz.data.counter  : ' .. domoticz.data.counter, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_10: ' .. domoticz.data.value_10, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_9 : ' .. domoticz.data.value_9, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_8 : ' .. domoticz.data.value_8, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_7 : ' .. domoticz.data.value_7, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_6 : ' .. domoticz.data.value_6, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_5 : ' .. domoticz.data.value_5, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_4 : ' .. domoticz.data.value_4, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_3 : ' .. domoticz.data.value_3, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_2 : ' .. domoticz.data.value_2, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_1 : ' .. domoticz.data.value_1, domoticz.LOG_DEBUG)
                domoticz.log('Plug Switch value_0 : ' .. domoticz.data.value_0, domoticz.LOG_DEBUG)

                if domoticz.data.value_9 > 1.48 * domoticz.data.value_0 then
                    -- switch off Plug Switch
                    domoticz.devices(CHARGER_SWITCH).switchOff()
                    domoticz.notify('Your battery has been charged',domoticz.PRIORITY_NORMAL)
                end
			else
				-- oops
				domoticz.log('Error fetching Plug Power data', domoticz.LOG_ERROR)
				domoticz.log(item.data, domoticz.LOG_ERROR)
			end
		end
	end
}
It stops charging somewhere between 85 and 95%

Almost forgot.
It sends a push notification to my phone when done.
Bugs bug me.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest