Is the washing machine done?

User avatar
felix63
Posts: 161
Joined: Monday 07 December 2015 10:30
Target OS: Raspberry Pi
Domoticz version: 3.8275
Location: Gouda
Contact:

Re: Is the washing machine done?

Post by felix63 » Tuesday 14 August 2018 18:09

I see my Raspberry is running 5 - 10% CPU load with peak unto 17%. But I don't know if that is due to this script.

I have include an optimalisation to the script adding a counter for keeping track of the number of active devices so to be able to skip the timer bit of the code if there are no active devices. Not thorough testing done yet 8-)
Spoiler: show

Code: Select all

 -- create a lookup table that matches a usage
 -- device to the accompanying switch
 local USAGE_DEVICES = {
 	['SC-Wasdroger verbruik'] = 'Wasdroger',	-- You need to have a inline wall plug that measures energy,
 	['SC-Wasmachine verbruik'] = 'Wasmachine',  -- here you make the link between the energy device and the wall plug.
 }

 local USAGE_SwitchTimeOutMinutes = {
 	['Wasdroger'] = 6,							-- Here you define how long no power is used per device.
 	['Wasmachine'] = 6,							-- The period is in minutes. Adjust to your needs. Between every add a ",".
 }

 local USAGE_MaxWatt = {
 	['Wasdroger'] = 3,							-- Here you define the maximum amount of power a device uses when it is in standby.
 	['Wasmachine'] = 3,							-- Some devices uses a little amount of power. Test it and a slightly higher usage.
 }

 local USAGE_Notify = {
 	['Wasdroger'] = 'Yes',						-- In some cases you want to be notified when a device is turned on and off.
 	['Wasmachine'] = 'Yes',						-- Adjust to your needs. Between every line you need to add a ",".
 }

 return {
 	logging = {
-- 		level = domoticz.LOG_INFO, 				-- Uncomment to override the dzVents global logging setting
-- 		marker = 'POW'
 	},

 	on = {
		timer = { 'every 5 minutes' },
 		devices = {								-- Make sure that the devices are the same as above
 			'SC-Wasdroger verbruik',
 			'SC-Wasmachine verbruik',
 		},
 	},
 	data = { 									-- use exact device names to match USAGE_DEVICES
        ['CountDevices'] = {initial=0},
 		['SC-Wasdroger verbruik'] = { history = true, maxMinutes = 10 },
 		['SC-Wasmachine verbruik'] = { history = true, maxMinutes = 10 }
 	},

 	execute = function(domoticz, device)
         if (device.isTimer) then
		 	if domoticz.data['CountDevices'] > 0) then
 			-- we need to check for expiration of grace period
 			domoticz.log("timer trigger")
 			for i, machine in pairs(USAGE_DEVICES) do
				local usage = "SC-" .. machine.. " verbruik"
 				domoticz.log("device = " .. machine)
 				local actual = domoticz.devices(usage).WhActual
 				local average = domoticz.data[usage].avg()
                domoticz.data[usage].add(actual)
 				domoticz.log("actual = " .. actual)
				domoticz.log("average = " .. tostring(average))
				if actual == 0 then
					domoticz.log(machine .. " gebruikt geen energie, dus is uit")
					domoticz.devices(machine).switchOff().checkFirst()
				elseif actual < USAGE_MaxWatt[machine] then
					domoticz.log(machine .. " gebruikt weinig energie, is de machine klaar?")
					local timeout = USAGE_SwitchTimeOutMinutes[machine]
					domoticz.log(machine .. " gebruikte gemiddeld: " .. tostring(domoticz.data[usage].avg))
					if (average <= USAGE_MaxWatt[machine]) then
						domoticz.log(machine .. " lijkt standby te staan, we nemen aan klaar.")
						domoticz.devices(machine).switchOff().checkFirst()
					    domoticz.data[usage].reset()
					else
						domoticz.log(machine .. " maar nog te kort om klaar te zijn.")
						domoticz.devices(machine).switchOn().checkFirst()
					end
				else 
					domoticz.log(machine .. " gebruikt energie, dus is (nog) bezig.")
					domoticz.devices(machine).switchOn().checkFirst()
				end
 			end
			end
 		elseif (USAGE_DEVICES[device.name] ~= nil) then
 			-- we have a usage sensor here
 			domoticz.log("usage trigger")
 			local switch = domoticz.devices(USAGE_DEVICES[device.name])
 			local timeout = USAGE_SwitchTimeOutMinutes[USAGE_DEVICES[device.name]]
 			local watt = USAGE_MaxWatt[USAGE_DEVICES[device.name]]
 			domoticz.data[device.name].add(device.WhActual)
 			local history = domoticz.data[device.name]
 			domoticz.log("device = " .. device.name)
 			if (switch.active) then
				domoticz.log("Switch is active, check average use and last update")
				domoticz.log("usage last update: " .. tostring(switch.lastUpdate.minutesAgo))
  			    domoticz.log("usage = " .. tostring(device.WhActual))
				domoticz.log("average = " .. tostring(history.avg()))
				if (history.avg() <= watt and device.WhActual <= watt and switch.lastUpdate.minutesAgo >= timeout) then
    			 	switch.switchOff().checkFirst()
					domoticz.log("Turn switch off")
    			    if domoticz.data['CountDevices'] > 0 then
						domoticz.data['CountDevices'] = domoticz.data['CountDevices'] - 1
					end
					domoticz.data[device.name].reset()
     			end
             else
				domoticz.log("Switch not on")
                 if (device.WhActual > watt) then
					domoticz.log("but power use is over treshold, turn switch on")
    			    domoticz.data['CountDevices'] = domoticz.data['CountDevices'] + 1
 	                switch.switchOn().checkFirst()
 	            end
 		    end
 		end
 	end
 }

akamming
Posts: 11
Joined: Friday 17 August 2018 14:03
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: Is the washing machine done?

Post by akamming » Saturday 08 September 2018 11:47

Thank you very much for this script.

i added some features for my situation, so posting my changed version back to this forum is my way of saying thank you to the original authors!

My additional needs were :
- The energy consumption of the Miele washing machine during the program is very low, it almost matches the pattern which is present after the finishing of some other washing programs (like 'kreukherstellend', sorry i do not know the english translation). this lead to wrong conclusions in the script and/or too notifications (resulting in an unhappy wife :oops: ) depending on how i set the paramets, but i could not get it to work. So i decided in my case the only generic way to detect if a the machine was finished its program is by checking the average. Since this also works for the other appliances, i removed the other detection method in the code
- i do not like to have too many virtual devices, so i wanted to user persistent vars instead.
- for tweaking the parameters to detect if a device is ready, i needed a logline which can be imported in Excel.

So i adapted the script to these needs, and now it works like a charm also in my situation (without the need of creating extra virtual devices in domoticz)

many thanks to the original authors of the code and keep up the good work!

Code: Select all

 
 -- create a lookup table that matches a usage
 -- device to the accompanying switch persistent variable
 local USAGE_DEVICES = {
 	['SC-Wasdroger verbruik'] = 'Wasdroger',		-- You need to have a inline wall plug that measures energy,
    ['SC-Wasmachine verbruik'] = 'Wasmachine',  	-- here you make the link between the energy device and the wall plug.
 	['SC-Vloerverwarming verbruik'] = 'Vloerverwarming',
 }

 local USAGE_SwitchTimeOutMinutes = {
 	['Wasdroger'] = 5,						-- Timeout after switching to prevent a lot of notifications when the situation is a little bit grey.
 	['Wasmachine'] = 5,	                    --
 	['Vloerverwarming'] = 1,
 }

 local USAGE_MaxWatt = {
 	['Wasdroger'] = 75,						-- Here you define the maximum amount of power a device uses when it is in standby.
 	['Wasmachine'] = 20,						-- Some devices uses a little amount of power. Test it and a slightly higher usage.
 	['Vloerverwarming'] = 5,
 }
 
  local USAGE_Notify = {
 	['Wasdroger'] = true,						-- In some cases you want to be notified when a device is turned on and off.
 	['Wasmachine'] = true,					-- Adjust to your needs. Between every line you need to add a ",".
 	['Vloerverwarming'] = true,
 }

 return {
 	logging = {
 		level = domoticz.LOG_DEBUG, 			-- Adjust to your needs
 		marker = 'AppliancesNotification-3'
 	},

 	on = {
		timer = { 'every minute' },
 		devices = { 
 		    'SC-Wasdroger verbruik', 
 		    'SC-Wasmachine verbruik'
 		} 
 	},
 	data = { 								-- use exact device names to match USAGE_DEVICES
 		['SC-Wasdroger verbruik'] = { history = true, maxMinutes = 3 },   -- persistent vars to record device history
 		['SC-Wasmachine verbruik'] = { history = true, maxMinutes = 5, maxItems = 300 }, -- choose maxMinutes as the time the average should be above maxwatt to indicate a running  appliance
 		['SC-Vloerverwarming verbruik'] = { history = true, maxMinutes = 1 },

 		['Wasdroger'] = { initial = false },    -- persistent var to store virtual switch
 		['Wasmachine'] = { initial = false },    -- use exact names to match USAGE_DEVICES
 		['Vloerverwarming'] = { initial = false },    

 		['Wasdroger LastUpdate'] = { initial = "2018-09-01 09:35:05" },    -- persistent var to store last update of virtual switch
 		['Wasmachine LastUpdate'] = { initial = "2018-09-01 09:35:05" },    -- use exact names to match USAGE_DEVICES, with " LastUpdate" added to the varname
 		['Vloerverwarming LastUpdate'] = { initial = "2018-09-01 09:35:05" },     -- timestamp should just be any timestamp in the past
 	},

 	execute = function(domoticz, item)
         -- Create Time Object
         local Time = require('Time')
         
         -- function to retrieve timestamp of lastupdate
         function GetLastUpdate(device)
             Timestring=domoticz.data[USAGE_DEVICES[device.name].." LastUpdate"]
             return Time(Timestring)  
         end
         
         -- flip the switch
         function SetSwitch(device,value)
            -- Set Switch value
         	domoticz.data[USAGE_DEVICES[device.name]]=value

         	-- Set Switch Timestamp
         	domoticz.data[USAGE_DEVICES[device.name].." LastUpdate"]=Time().raw
         	
         	-- for debuggin purposes
          	domoticz.log("Switch "..USAGE_DEVICES[device.name].." was put to "..tostring(domoticz.data[USAGE_DEVICES[device.name]]).." on "..GetLastUpdate(device).raw)
          	
          	-- Check if we have to notify
          	if (USAGE_Notify[USAGE_DEVICES[device.name]]) then
          	    if (value) then
          	        NotificatonMessage='De '..USAGE_DEVICES[device.name].." is aan"
      	        else
          	        NotificatonMessage='De '..USAGE_DEVICES[device.name].." is klaar"
  	            end
          	    domoticz.notify(USAGE_DEVICES[device.name],NotificatonMessage,domoticz.PRIORITY_HIGH)
          	    domoticz.log("Notification sent: "..NotificatonMessage)
      	    end
         end

 	    
 	    -- check values of 1 device and act on it if needed
 	     function CheckAppliance(device)
 			domoticz.log("Checking device " .. device.name)

 	        -- retrieve the needed data
			local timeout = USAGE_SwitchTimeOutMinutes[USAGE_DEVICES[device.name]]
 			local watt = USAGE_MaxWatt[USAGE_DEVICES[device.name]]
 			domoticz.data[device.name].add(device.WhActual)
 			local history = domoticz.data[device.name]
 			local UpdateTime = GetLastUpdate(device)
 			
			-- for debugging purposes
			domoticz.log("switch last update in minutes: " .. tostring(UpdateTime.minutesAgo))
  		    domoticz.log("usage = " .. tostring(device.WhActual))
			domoticz.log("average = " .. tostring(history.avg()))
			domoticz.log("timeout = "..timeout)
			domoticz.log("MaxWatt = "..watt)
			
			-- for analysing the log to finetune the parameters of the appliances: Log a line which can be imported in excel
			domoticz.log("Import:"..device.name..";"..tostring(UpdateTime.minutesAgo)..";"..tostring(device.WhActual)..";"..tostring(history.avg())..";"..timeout..";"..watt)

            -- analyse the values and perform actions if needed
    		if (domoticz.data[USAGE_DEVICES[device.name]]) then
				if (history.avg() <= watt and device.WhActual <= watt and UpdateTime.minutesAgo >= timeout) then
					domoticz.log("average power use is under treshold, turning switch off")
					SetSwitch(device,false)
				else 
				    domoticz.log("actual or average power use is above treshold or timeout still active, leave switch on")
     			end
             else
                 if (history.avg() >watt and device.WhActual >watt and UpdateTime.minutesAgo >= timeout) then
					domoticz.log("average power use is above treshold, turning switch on")
					SetSwitch(device,true)
                 else
                    domoticz.log("actual or average power use is under treshold or timeout still active, leave switch off")
 	            end
 		    end
 	    end
 	
 	    -- it the trigger was the timer, all devices should be triggered
 	    if (item.isTimer) then
 			domoticz.log("timer trigger, Check all devices")
     	    -- loop through appliances 
     	    for i, machine in pairs(USAGE_DEVICES) do
     			CheckAppliance(domoticz.devices(i))
     			domoticz.log("---------------------------------------------------------------------")
            end
        end
    
        -- it the triggered was a device: Check this device
 	    if (item.isDevice) then
 			domoticz.log("device trigger, Check updated device")
 	        CheckAppliance(item)
        end
 	end
 }

mcmikev
Posts: 150
Joined: Tuesday 26 May 2015 8:11
Target OS: Raspberry Pi
Domoticz version: beta
Location: right here
Contact:

Re: Is the washing machine done?

Post by mcmikev » Saturday 08 September 2018 12:25

Thanks for your updated script.

I too have/had false "Vaatwasser klaar, of wasmachine klaar" notifications. So I want to try this version.

Can you tell me what vars you need and what type those are ? (String, Integer, date or time?)

Hope you are willing to explain!!

akamming
Posts: 11
Joined: Friday 17 August 2018 14:03
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: Is the washing machine done?

Post by akamming » Saturday 08 September 2018 14:19

mcmikev wrote:
Saturday 08 September 2018 12:25
Thanks for your updated script.

I too have/had false "Vaatwasser klaar, of wasmachine klaar" notifications. So I want to try this version.

Can you tell me what vars you need and what type those are ? (String, Integer, date or time?)

Hope you are willing to explain!!

I don't fully understand your question. The persistent vars are declared in the "date = { } " section. So you have to put your 'vaatwasser' and 'wasmachine' there as well. you do not have to specify the type. if you have a bit of scripting skills (like me, i am not an experienced programmer) and follow the comments you should be able to make it work.

User avatar
felix63
Posts: 161
Joined: Monday 07 December 2015 10:30
Target OS: Raspberry Pi
Domoticz version: 3.8275
Location: Gouda
Contact:

Re: Is the washing machine done?

Post by felix63 » Saturday 08 September 2018 15:42

akamming wrote:
Saturday 08 September 2018 11:47
- i do not like to have too many virtual devices, so i wanted to user persistent vars instead.
The reason I created virtual devices in this instance was because I like to attach notifications to a switch using the Domoticz standard notifications. This way the notifications are separate from the scripting and more easily maintainable. I know it's a a quirk...

akamming
Posts: 11
Joined: Friday 17 August 2018 14:03
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: Is the washing machine done?

Post by akamming » Saturday 08 September 2018 16:05

felix63 wrote:
Saturday 08 September 2018 15:42
The reason I created virtual devices in this instance was because I like to attach notifications to a switch using the Domoticz standard notifications. This way the notifications are separate from the scripting and more easily maintainable. I know it's a a quirk...
I understand your point. My problem is that using virtual switch in the ui i get a device which i can switch on or off which should not be possible and therefore is confusing.

On the other hand i am very new to this scripting and domoticz, so maybe i miss something. Would it be possible to create a switch (or even better: a status indicator) which does display the state of the appliance, but cannot be overruled in the user interface of domoticz...

User avatar
felix63
Posts: 161
Joined: Monday 07 December 2015 10:30
Target OS: Raspberry Pi
Domoticz version: 3.8275
Location: Gouda
Contact:

Re: Is the washing machine done?

Post by felix63 » Thursday 13 September 2018 17:28

That's very simple. You can 'protect' switches. Meaning that the value can not be changed by either the user or by json calls. When you go to the tab with the device and click on the gear icon to edit the properties you can click 'protect'. Then you can no longer 'accidentally' change it because you are asked for a password.

akamming
Posts: 11
Joined: Friday 17 August 2018 14:03
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: Is the washing machine done?

Post by akamming » Saturday 15 September 2018 20:38

Nice... i will try it. Currently not in a hurry.. i have a working script now :)

Post Reply

Who is online

Users browsing this forum: Huntback and 0 guests