Just to update myself again for anybody that finds it useful, Claude.ai is pretty fluent in dzvents
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¶m=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.