Page 1 of 1

universal notification function, with parametric reminder time?

Posted: Monday 14 January 2019 20:04
by renerene
"The battery is low, replace it" (once per day)
"the door is open and it's freezing outside" (every 5 minutes)


These are two typical messages that can be sent as log, notification or spoken on Alexa/Google/Jarvis@home.
Mostly it is triggered by a script, multiple time each hour. Because I don't want notification bombs there is some sort of 'once per day' variable, that is resetted once per day.

This can be done more efficient.

Recently I found out the universal helper scripts in dzVents. I am thinking about writing an universal routine, with following parameters:
function report (message, log, speak, notify, muteTimeMin)

Question
How to program the muteTimeMin part? Ideas welcome.

So, for instance,

Code: Select all

if previousMessage.minutesAgo > muteTimeMin then 
     notitfy message 
     reset muteTime
else
     keep Quiet and wait some more
end

Offcourse, there will be more messages going on at the same time and domoticz need to keep track of the time when each message was notified.

Re: universal notification function, with parametric reminder time?

Posted: Monday 14 January 2019 21:51
by waaren
renerene wrote: Monday 14 January 2019 20:04 "The battery is low, replace it" (once per day)
"the door is open and it's freezing outside" (every 5 minutes)

These are two typical messages that can be sent as log, notification or spoken on Alexa/Google/Jarvis@home.
Mostly it is triggered by a script, multiple time each hour. Because I don't want notification bombs there is some sort of 'once per day' variable, that is resetted once per day.
function report (message, log, speak, notify, muteTimeMin)
Question
How to program the muteTimeMin part? Ideas welcome.

Offcourse, there will be more messages going on at the same time and domoticz need to keep track of the time when each message was notified.
Nice idea !

What about this ?

Code: Select all

-- global_data.lua 
 
return {
    
        data = {
                       managedNotifications                    = { initial = {}},
                  },

	helpers =   {
                    managedNotify = function (dz, message, messageType, muteTimeMin,quietHours) 
                        local now = os.time(os.date('*t'))                  -- seconds since 1/1/1970 00:00:01
                        muteTimeMin = muteTimeMin or 1
                        
                        if ( not dz.globalData.managedNotifications[message] ) or 
                           (( dz.globalData.managedNotifications[message] + muteTimeMin * 60 ) <= now ) then
                                if quietHours and dz.time.matchesRule("at " .. quietHours) then
                                    dz.log("Quiet hours: no notification.") .. 
                                else
                                    dz.notify("managedNotification", message,nil,nil,nil,messageType)  
                                    dz.globalData.managedNotifications[message] = now
                                end     
                        else
                            -- No action required yet.  
                            dz.log("Last '" .. message .. "' message was send at " .. 
                                    os.date("%A, %d %B %Y (%H:%M)",dz.globalData.managedNotifications[message]) ,dz.LOG_FORCE)
                       end
                    end,
                },
       }

Code: Select all

-- managedNotify test script

return {
   on = { timer = { "every minute" }},    
   
   execute = function(dz)
   
       -- 1st parm (dz)        required 
       -- 2nd parm (message)   required
       -- 3rd parm (notification subsystem) optional but required if any of the next parms in use (when nil defaults to all)
       -- 4th parm (frequency in minutes) optional and defaults to 1 but required when using 5th parm.
       -- 5th parm (quiet hours) optional        
   
       dz.helpers.managedNotify(dz, "first message",  dz.NSS_PUSHOVER, 4)        
       dz.helpers.managedNotify(dz, "Next message",  dz.NSS_TELEGRAM, 3)        
       dz.helpers.managedNotify(dz, "Third message",  dz.NSS_GOOGLE_CLOUD_MESSAGING, 7,"10:59-11:15")     -- last parm optional
       dz.helpers.managedNotify(dz, "4th message",  dz.NSS_TELEGRAM, 1 ,"21:00-11:36")        
       dz.helpers.managedNotify(dz, "5th message")        
       dz.helpers.managedNotify(dz, "6th message",nil,15)        
   end
}


Re: universal notification function, with parametric reminder time?

Posted: Monday 14 January 2019 23:10
by renerene
This. Is. Awesome
thank you/respect!

Re: universal notification function, with parametric reminder time?

Posted: Tuesday 15 January 2019 8:55
by freijn
Very interesting, but please help me understand.

Where do I put the -- global_data.lua script so the -- managedNotify test script can find the function ?

Re: universal notification function, with parametric reminder time?

Posted: Tuesday 15 January 2019 9:16
by elmortero

Re: universal notification function, with parametric reminder time?

Posted: Tuesday 15 January 2019 9:46
by waaren
freijn wrote: Tuesday 15 January 2019 8:55 Very interesting, but please help me understand.

Where do I put the -- global_data.lua script so the -- managedNotify test script can find the function ?
in the script directory.

Note: there can be only one global_data.lua on your system. Either in /path/to/domoticz/scripts/dzVents/script or in Domoticz' internal GUI web editor.

Re: universal notification function, with parametric reminder time?

Posted: Tuesday 15 January 2019 11:46
by waaren
Edited my example (see post #2) to include optional quiet hours.

Re: universal notification function, with parametric reminder time?

Posted: Saturday 26 January 2019 23:02
by renerene
Can a purge function be added?

I use this routine now my main notification tool. Often there is a variable in the text ("temperature is..") which makes the index of the managedNotifications table unique, making the mute function not work for the same message type with another variable value. This is not a big issue. But I don't like the idea of the table building up with values that will be never looked after again.

Therefore: do a once per week purge of messages older than 30 days?

Re: universal notification function, with parametric reminder time?

Posted: Sunday 27 January 2019 1:53
by waaren
renerene wrote: Saturday 26 January 2019 23:02 Can a purge function be added?
sure. It is already possible to do that by removing the data file. It will be recreated using the initial values, the next time the global_data script executes.
I use this routine now my main notification tool. Often there is a variable in the text ("temperature is..") which makes the index of the managedNotifications table unique, making the mute function not work for the same message type with another variable value. This is not a big issue. But I don't like the idea of the table building up with values that will be never looked after again.
Therefore: do a once per week purge of messages older than 30 days?
In below script, I added subject as a parameter. This does mean that your scripts calling this helper function need to be modified to insert the subject as 2nd parameter. :!: :!:

Extra's:
  • using the subject "delete" will cause the managedNotify table entry with the index "message" to be removed
  • using the subject "deleteAll"will cause all managedNotify table entries to be removed.
  • managedNotify table entries for a message, created 30 days ago or earlier, will be removed when any new message will be added to this table

Code: Select all

-- global_data.lua 
 
return {
        data =  {
                    managedNotifications                    = { initial = {}},
                },
	helpers =   {
                    managedNotify = function (dz, subject,message, messageType, muteTimeMin,quietHours) 
                        local now = os.time(os.date('*t'))                  -- seconds since 1/1/1970 00:00:01
                        muteTimeMin = muteTimeMin or 1
                        if subject == nil or string.lower(subject) == "delete"  then 
                            dz.globalData.managedNotifications[message] = nil 
                            dz.log("message " .. message .. "  on request deleted",dz.LOG_FORCE)
                            return 3
                        elseif string.lower(subject) ==  "deleteall" then
                            dz.globalData.managedNotifications = nil 
                            dz.log("All messages on request deleted",dz.LOG_FORCE)
                            return 4
                        elseif ( not dz.globalData.managedNotifications[message] ) or 
                              (( dz.globalData.managedNotifications[message] + muteTimeMin * 60 ) <= now ) then
                                if quietHours and dz.time.matchesRule("at " .. quietHours) then
                                    dz.log("Quiet hours: no notification.")
                                    return 1
                                else
                                    dz.notify(subject, message,nil,nil,nil,messageType)  
                                    dz.globalData.managedNotifications[message] = now
                                    local cleanupPeriod = 30 * 24 * 3600                                -- 30 days
                                    for key,timeStamp in pairs(dz.globalData.managedNotifications) do
                                        if ( dz.globalData.managedNotifications[key] + cleanupPeriod ) < now then 
                                            dz.globalData.managedNotifications[key] = nil
                                            dz.log("(Old) message " .. key .. "  deleted",dz.LOG_FORCE)
                                        end
                                    end
                                    return 0
                                end     
                        else
                            -- No action required yet.  
                            dz.log("Last '" .. message .. "' message was send at " .. 
                                    os.date("%A, %d %B %Y (%H:%M)",dz.globalData.managedNotifications[message]) ,dz.LOG_FORCE)
                            return 2        
                        end
                    end,
                },
        }

Code: Select all

-- managedNotify test script

return {
   on = { timer = { "every minute" }},    
   
   execute = function(dz)
   
       -- 1st parm (dz)        required 
       -- 2nd parm (subject)   if nil or "deleted" then table entry for message will be removed
       --                      if "deleteAll" then all table entries will be removed
       --                      else required => notification subject 
       -- 3rd parm (message)   required except when subject is "deleteAll"
       -- 4th parm (notification subsystem) optional but required if any of the next parms in use (when nil defaults to all)
       -- 5th parm (frequency in minutes) optional and defaults to 1 but required when using 6th parm.
       -- 6th parm (quiet hours) optional        
   
      -- dz.helpers.managedNotify(dz, "testMessage_1", "first message",  dz.NSS_PUSHOVER,               4)        
      -- dz.helpers.managedNotify(dz, "testMessage_2", "Next message",   dz.NSS_TELEGRAM,               3)        
      -- dz.helpers.managedNotify(dz, "testMessage_3", "Third message",  dz.NSS_GOOGLE_CLOUD_MESSAGING, 7, "10:59-11:15")
      -- dz.helpers.managedNotify(dz, "testMessage_4", "4th message",    dz.NSS_TELEGRAM,               1, "22:00-11:36")        
      -- dz.helpers.managedNotify(dz, "testMessage_5", "5th message",    dz.NSS_TELEGRAM,             120 )        
      -- dz.helpers.managedNotify(dz, "testMessage_6", "6th message",    nil,                          15 )        
      
      -- dz.helpers.managedNotify(dz, "delete","6th message") -- the will remove table entry with key 
      -- dz.helpers.managedNotify(dz, "deleteAll") -- the will remove all notifications in table 
   end 
}