dzvents reset a timer with a switch for air filter swap

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

Moderator: leecollings

Post Reply
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

We have mechanical ventilation, and I need to swap out the filters every 6 months.
So I'm looking for a dzvents script that would trigger a switch to be toggled to on.
The 6 month timer should start again after I set the switch to off again.

I'm not sure how and of this is possible in dzvents
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

Just put this into Claude.ai, and I think this is a good starting point.

Code: Select all

-- Filter Change Reminder Script
return {
    on = {
        devices = {
            'Filter_Change_Switch' -- Replace with your actual switch name
        },
        timer = {
            'at 00:00' -- Check daily at midnight
        }
    },
    data = {
        lastReset = { initial = 0 }
    },
    execute = function(domoticz, device)
        local filterSwitch = domoticz.devices('Filter_Change_Switch')
        local currentTime = os.time()
        local sixMonths = 180 * 24 * 60 * 60 -- 180 days in seconds
        
        if device.isTimer then
            -- Check if 6 months have passed since last reset
            if (currentTime - domoticz.data.lastReset) >= sixMonths then
                filterSwitch.switchOn()
            end
        elseif device.state == 'Off' then
            -- Reset timer when switch is turned off
            domoticz.data.lastReset = currentTime
        end
    end
}
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

If anybody is interested, I ended up with this.

Code: Select all

-- Filter Change Reminder Script
local scriptVar = 'WTW_Filter_Reset'
local WTWFilterResetidx = 4091

-- Configuration
local reminderDays = 180  -- Number of days before triggering the switch
local reminderSeconds = reminderDays * 24 * 60 * 60  -- Convert days to seconds

return {
    on = {
        devices = {
            WTWFilterResetidx
        },
        timer = {
            'at 00:00' -- Check daily at midnight
        }
    },
    logging = {
        level = domoticz.LOG_DEBUG,
        marker = scriptVar
    },
    data = {
        lastReset = { initial = 0 }
    },
    execute = function(domoticz, device)
        domoticz.log('Script execution started', domoticz.LOG_DEBUG)
        
        local filterSwitch = domoticz.devices(WTWFilterResetidx)
        local currentTime = os.time()
        
        if device.isTimer then
            domoticz.log('Triggered by timer', domoticz.LOG_DEBUG)
        else
            domoticz.log('Triggered by device: ' .. device.name, domoticz.LOG_DEBUG)
        end
        
        domoticz.log(string.format('Current time: %s', os.date('%Y-%m-%d %H:%M:%S', currentTime)), domoticz.LOG_DEBUG)
        domoticz.log(string.format('Last reset time: %s', os.date('%Y-%m-%d %H:%M:%S', domoticz.data.lastReset)), domoticz.LOG_DEBUG)
        
        if device.isTimer then
            local timeElapsed = currentTime - domoticz.data.lastReset
            local timeRemaining = reminderSeconds - timeElapsed
            local daysRemaining = math.floor(timeRemaining / (24 * 60 * 60))
            
            domoticz.log(string.format('Time since last reset: %d seconds', timeElapsed), domoticz.LOG_DEBUG)
            domoticz.log(string.format('Time remaining: %d seconds', timeRemaining), domoticz.LOG_DEBUG)
            domoticz.log(string.format('Days remaining until next filter change: %d', daysRemaining), domoticz.LOG_DEBUG)
            
            if timeElapsed >= reminderSeconds then
                domoticz.log(string.format('%d days elapsed - turning on filter change reminder switch', reminderDays), domoticz.LOG_DEBUG)
                filterSwitch.switchOn()
            else
                domoticz.log('Time threshold not yet reached', domoticz.LOG_DEBUG)
            end
        elseif device.state == 'Off' then
            domoticz.data.lastReset = currentTime
            domoticz.log('Switch turned off - resetting timer', domoticz.LOG_DEBUG)
            domoticz.log(string.format('New timer start time: %s', os.date('%Y-%m-%d %H:%M:%S', currentTime)), domoticz.LOG_DEBUG)
        end
        
        domoticz.log('Script execution completed', domoticz.LOG_DEBUG)
    end
}
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

Just to update myself again for anybody that finds it useful, Claude.ai is pretty fluent in dzvents :D

Domoticz WTW Filter Reset Script with Auto-Hiding and Pushover Notifications

The goal was to create a reminder system that would automatically notify when filters need replacement, while keeping the UI clean by hiding the device when not needed.

What the Script Does:
- Tracks when WTW filters need to be replaced (configurable, default 180 days)
- Automatically hides the device in normal operation using a $ prefix
- Makes the device visible and sends notifications when approaching replacement time
- Sends a warning notification 7 days before replacement is due
- When the replacement date is reached, makes the device visible and turns it ON
- After replacing filters and turning the switch OFF, resets the timer and hides the device again

Required Files:
The script requires two files:

1. The main script (WTW_Filter_Reset.lua)
2. A global_data.lua file for Pushover notifications

global_data.lua Configuration:
First, create or update your global_data.lua with this Pushover configuration:

Code: Select all

return {
    data = {},
    helpers = {
        PUSHOVER = {
            -- User Keys - Replace with your Pushover user keys
            USERS = {
                USER1 = 'your_user_key_here',
                USER2 = 'another_user_key_here',
                FAMILY = 'family_group_key_here',
            },
            -- App Keys - Replace with your Pushover application tokens
            APPS = {
                HOME = 'your_app_token_here',
                TEST = 'test_app_token_here',
                DOMOTICZ = 'domoticz_app_token_here',
            },
            -- Priority levels (don't change these)
            PRIORITY = {
                LOWEST = -2, 
                LOW = -1, 
                NORMAL = 0, 
                HIGH = 1, 
                EMERGENCY = 2
            },
            -- Available notification sounds
            SOUNDS = {
                PUSHOVER = 'pushover',
                BIKE = 'bike',
                BUGLE = 'bugle',
                COSMIC = 'cosmic',
                VIBRATE = 'vibrate',
                NONE = 'none',
            },
            -- TTL presets in seconds
            TTL = {
                ONE_MINUTE = 60,
                ONE_HOUR = 3600,
                ONE_DAY = 86400,
                ONE_WEEK = 604800,
            },
        },

        -- Enhanced pushover function with TTL support
        pushover = function(domoticz, scriptVar, PushoverUser, PushoverApp, title, message, priority, sound, ttl)
            -- Input validation
            assert(PushoverUser, 'PushoverUser is required')
            assert(PushoverApp, 'PushoverApp is required')
            assert(message, 'Message is required')

            -- Use defaults if not provided
            title = title or domoticz.helpers.PUSHOVER.DEFAULTS.TITLE
            priority = priority or domoticz.helpers.PUSHOVER.DEFAULTS.PRIORITY
            sound = sound or domoticz.helpers.PUSHOVER.DEFAULTS.SOUND

            -- TTL validation when provided
            if ttl then
                assert(type(ttl) == 'number' and ttl > 0, 'TTL must be a positive number of seconds')
                -- TTL is ignored for emergency priority
                if priority == domoticz.helpers.PUSHOVER.PRIORITY.EMERGENCY then
                    domoticz.log('TTL is ignored for emergency priority messages', domoticz.LOG_DEBUG)
                    ttl = nil
                end
            end

            -- Logging
            domoticz.log(
                    string.format(
                            'Sending Pushover notification - User: %s, App: %s, Title: %s, Sound: %s, TTL: %s',
                            PushoverUser, PushoverApp, title or 'No title',
                            sound or domoticz.helpers.PUSHOVER.DEFAULTS.SOUND, ttl or 'No TTL'
                    ), domoticz.LOG_DEBUG
            )

            -- Prepare post data
            local postData = {
                token = PushoverApp,
                user = PushoverUser,
                message = message,
                title = title or domoticz.helpers.PUSHOVER.DEFAULTS.TITLE,
                priority = priority or domoticz.helpers.PUSHOVER.DEFAULTS.PRIORITY,
                sound = sound or domoticz.helpers.PUSHOVER.DEFAULTS.SOUND,
            }

            -- Add TTL if specified
            if ttl then
                postData.ttl = ttl
            end

            -- Send notification
            domoticz.openURL(
                    {
                        url = 'https://api.pushover.net/1/messages.json',
                        method = 'POST',
                        postData = postData,
                        callback = function(response)
                            if response.isError then
                                domoticz.log(
                                    'Failed to send Pushover notification: ' .. response.data, domoticz.LOG_ERROR
                                )
                            else
                                domoticz.log('Pushover notification sent successfully!', domoticz.LOG_INFO)
                            end
                        end,
                    }
            )
        end,
    },
}
Main Script Configuration:

Code: Select all

local scriptVar = 'WTW_Filter_Reset'

-- Get global data for helpers
local GlobalData = require('global_data')

-- Configuration
local CONFIG = {
    DEVICE_IDX = 4091,
    REMINDER_DAYS = 180,
    VISIBLE_NAME = 'WTW Filter Reset',
    HIDDEN_NAME = '$WTW Filter Reset',  -- Using $ for proper hiding
    CHECK_INTERVAL = 'at 00:00',
    WARNING_THRESHOLD_DAYS = 7  -- Days before reminder to show warning
}

-- Calculate seconds from days
local REMINDER_SECONDS = CONFIG.REMINDER_DAYS * 24 * 60 * 60

return {
    on = {
        devices = {
            CONFIG.DEVICE_IDX
        },
        timer = {
            CONFIG.CHECK_INTERVAL
        }
    },
    
    logging = {
        level = domoticz.LOG_DEBUG,
        marker = scriptVar
    },
    
    data = {
        lastReset = { initial = 0 },
        lastWarningDay = { initial = -1 }
    },
    
    execute = function(domoticz, item)
        local function logDebug(message)
            domoticz.log(message, domoticz.LOG_DEBUG)
        end

        local function logError(message)
            domoticz.log(message, domoticz.LOG_ERROR)
        end
        
        local function formatDateTime(timestamp)
            return os.date('%Y-%m-%d %H:%M:%S', timestamp)
        end
        
        local function sendNotification(title, message, isHighPriority, ttlDays)
            if GlobalData and GlobalData.helpers and GlobalData.helpers.pushover then
                GlobalData.helpers.pushover(
                    domoticz,
                    scriptVar,
                    GlobalData.helpers.PUSHOVER.USERS.USER1,
                    GlobalData.helpers.PUSHOVER.APPS.HOME,
                    title,
                    message,
                    isHighPriority and GlobalData.helpers.PUSHOVER.PRIORITY.HIGH 
                                  or GlobalData.helpers.PUSHOVER.PRIORITY.LOW,
                    isHighPriority and GlobalData.helpers.PUSHOVER.SOUNDS.VIBRATE 
                                  or GlobalData.helpers.PUSHOVER.SOUNDS.NONE,
                    ttlDays and (ttlDays * 24 * 60 * 60) or GlobalData.helpers.PUSHOVER.TTL.ONE_DAY
                )
            else
                logError('Global helpers not available for notifications')
                domoticz.notify(
                    title,
                    message,
                    isHighPriority and domoticz.PRIORITY_HIGH or domoticz.PRIORITY_LOW
                )
            end
        end
        
        local function isDeviceVisible(device)
            return device.name == CONFIG.VISIBLE_NAME
        end
        
        local function updateDeviceVisibility(device, shouldBeVisible)
            if not device then
                logError('Cannot update visibility: device not found')
                return
            end

            local currentlyVisible = isDeviceVisible(device)
            local newName = shouldBeVisible and CONFIG.VISIBLE_NAME or CONFIG.HIDDEN_NAME
            
            logDebug(string.format('Current device name: "%s"', device.name))
            logDebug(string.format('Current visibility: %s', tostring(currentlyVisible)))
            logDebug(string.format('Requested visibility: %s', tostring(shouldBeVisible)))
            
            if currentlyVisible ~= shouldBeVisible then
                logDebug(string.format('Renaming device to: "%s"', newName))
                
                -- Base URL for Domoticz API
                local baseUrl = 'http://127.0.0.1:8080'
                
                -- Use renamedevice command with full URL
                local url = string.format('%s/json.htm?type=command&param=renamedevice&idx=%d&name=%s', 
                    baseUrl,
                    CONFIG.DEVICE_IDX, 
                    domoticz.utils.urlEncode(newName)
                )
                logDebug('Attempting to rename using setused command: ' .. url)
                
                domoticz.openURL({
                    url = url,
                    method = 'GET',
                    callback = function(response)
                        if response.status == 200 then
                            logDebug('Rename command sent successfully')
                        else
                            logError('Failed to send rename command: ' .. (response.statusText or 'unknown error'))
                        end
                    end
                })
                
                -- Log the rename attempt
                logDebug(string.format('Rename command sent for device %d', CONFIG.DEVICE_IDX))
            else
                logDebug('Device already in correct visibility state')
            end
        end
        
        -- Main execution starts here
        logDebug('Script execution started')
        
        local filterSwitch = domoticz.devices(CONFIG.DEVICE_IDX)
        if not filterSwitch then
            logError('Filter switch device not found')
            return
        end

        local currentTime = os.time()
        
        logDebug(string.format('Current time: %s', formatDateTime(currentTime)))
        logDebug(string.format('Last reset time: %s', formatDateTime(domoticz.data.lastReset)))
        
        -- Handle manual reset (switch turned off)
        if item.isDevice and item.state == 'Off' then
            logDebug('Switch turned off - resetting timer')
            domoticz.data.lastReset = currentTime
            domoticz.data.lastWarningDay = -1
            logDebug(string.format('New timer start time: %s', formatDateTime(currentTime)))
            updateDeviceVisibility(filterSwitch, false)  -- Hide device when reset
            
        -- Handle timer-based checks
        elseif item.isTimer then
            logDebug('Triggered by timer')
            
            local timeElapsed = currentTime - domoticz.data.lastReset
            local timeRemaining = REMINDER_SECONDS - timeElapsed
            local daysRemaining = math.floor(timeRemaining / (24 * 60 * 60))
            
            logDebug(string.format('Days remaining until next filter change: %d', daysRemaining))
            
            -- Time to replace filter
            if timeElapsed >= REMINDER_SECONDS then
                logDebug(string.format('%d days elapsed - activating filter change reminder', CONFIG.REMINDER_DAYS))
                filterSwitch.switchOn()  -- Turn switch on
                updateDeviceVisibility(filterSwitch, true)  -- Make visible
                
                -- Only send notification if state just changed
                if not isDeviceVisible(filterSwitch) then
                    sendNotification(
                        'WTW',
                        'WTW filters moeten vervangen worden',
                        true,
                        1
                    )
                end
            
            -- Approaching filter change date
            elseif daysRemaining <= CONFIG.WARNING_THRESHOLD_DAYS then
                logDebug(string.format('Approaching filter change date - %d days remaining', daysRemaining))
                updateDeviceVisibility(filterSwitch, true)  -- Make visible
                
                -- Send warning notification only once for each remaining day
                if daysRemaining ~= domoticz.data.lastWarningDay then
                    sendNotification(
                        'WTW',
                        string.format('WTW filters moeten binnenkort vervangen worden (nog %d dagen)', daysRemaining),
                        false,
                        7
                    )
                    domoticz.data.lastWarningDay = daysRemaining
                end
            
            -- Normal operation
            else
                logDebug('Time threshold not yet reached')
                updateDeviceVisibility(filterSwitch, false)  -- Keep hidden
                domoticz.data.lastWarningDay = -1
            end
        end
        
        logDebug('Script execution completed')
    end
}
Installation Steps:
1. Set up Pushover:
- Create a Pushover account at pushover.net
- Create an application to get your APP token
- Get your USER key from your account
- Update global_data.lua with your keys

2. Create the device:
- Add a dummy switch in Domoticz
- Note its idx number
- Update the DEVICE_IDX in the script

3. Install the scripts:
- Place global_data.lua in your dzVents scripts folder
- Create WTW_Filter_Reset.lua with the main script
- Update CONFIG settings as needed

Usage:
The script runs automatically and will:
1. Stay hidden during normal operation
2. Send a warning notification 7 days before replacement is due
3. Make the device visible and turn it ON when filters need replacement
4. Hide again after you replace filters and turn the switch OFF


Production Tips:
- Change CHECK_INTERVAL to 'at 00:00' for daily checks
- Adjust WARNING_THRESHOLD_DAYS based on your needs
- Consider adding more users to the Pushover notifications
- Test the script with shorter intervals initially, and check debug log

Note: Remember to replace the Pushover keys in global_data.lua with your actual Pushover tokens and keys before using the script.
User avatar
waltervl
Posts: 5397
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by waltervl »

Why use your own global_data pushover notification function when dzvents notify() function also can send notifications to pushover with standard Domoticz pushover integration?
https://wiki.domoticz.com/Notifications ... g_Pushover
https://wiki.domoticz.com/DzVents:_next ... nd_methods
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

The main reason is that it gives me more flexibility with Pushover.
I have many different Apps in Pushover for Domoticz, thinks like Alarms, House, Washing machine, Server, etc.
That way they all have their own icon, set TTL, etc

To my knowledge that is not possible with Domoticz notify()
Kedi
Posts: 564
Joined: Monday 20 March 2023 14:41
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Somewhere in NL
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Kedi »

WOW, so that is what Claude.ai does? So complicated. I use my phone agenda for this.
Logic will get you from A to B. Imagination will take you everywhere.
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

Yeah, I was really surprised how well it is able to generate scripts for Domoticz. ChatGPT can do it but is not that good with it.
With Claude.ai you still need to understand dzvents to help it guide to the correct outcome but it is pretty good.
HvdW
Posts: 539
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by HvdW »

BTW
I don't understand why you don't make a simple note in your 📆 to warn you to change filters which can be repeated every 6 months.

I'm using the Google option in domoticz for notifications and it works very well.
Did you discover the domoticz systeem alive checker?
It's a very handy tool.
Bugs bug me.
User avatar
Ragdag
Posts: 126
Joined: Friday 30 March 2018 13:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by Ragdag »

HvdW wrote: Tuesday 04 February 2025 20:31 BTW
I don't understand why you don't make a simple note in your 📆 to warn you to change filters which can be repeated every 6 months.

I'm using the Google option in domoticz for notifications and it works very well.
Did you discover the domoticz systeem alive checker?
It's a very handy tool.
That is how I did it before with just a calendar, just wanted to have it all in Domoticz and enjoyed figuring this out
HvdW
Posts: 539
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: dzvents reset a timer with a switch for air filter swap

Post by HvdW »

I can imagine you do.
Same for me. Writing dzVents scripts is so much fun, even totaly unnecessary scripts.
I have CoPilot, Deep Seek and Claude to help me.
The first ones for the dumb programming, Claude for refinement and efficient programming.
I do agree that Claude is superior.
In addition: Claude respects our privacy and the other two don't. CoPilot reads your underlying EDGE tab.
Bugs bug me.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests