script on = {timer......

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

Moderator: leecollings

Post Reply
Knibor
Posts: 112
Joined: Sunday 20 May 2018 12:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: NL
Contact:

script on = {timer......

Post by Knibor »

Hi,

Is it possible to let run a script not every minute but every 30 seconds?

on = { timer = { 'every minute'},

Thanks
Last edited by Knibor on Sunday 19 July 2020 21:21, edited 1 time in total.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: script on = {timer......

Post by waaren »

Knibor wrote: Sunday 19 July 2020 15:08 Is it possible to let rum a script not every minute but every 30 seconds?
Yes see below script

Code: Select all

local scriptVar = 'myCustomTimer'

return
{
    on =
    {
        timer =
        {
            'every minute',
        },

        customEvents =
        {
            scriptVar .. '*',  -- event triggered by emitEvent
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG, -- change to domoticz.LOG_ERROR when all is OK
       marker = scriptVar,
    },

    execute = function(dz, item)

        local every = 30 -- Frequency ==>>  the script should execute every nn seconds (min 1, max 30)

        if item.isCustomEvent then
            dz.log('Triggered by customEvent ' .. item.trigger, dz.log_DEBUG)
        else
            dz.log('Triggered by timer',dz.LOG_DEBUG)
            for i = every, (60 - every), every do
                dz.emitEvent(scriptVar .. ' after ' .. i .. ' seconds' ).afterSec(i)
            end
        end

        -- Rest of sript logic should go here
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Knibor
Posts: 112
Joined: Sunday 20 May 2018 12:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: NL
Contact:

Re: script on = {timer......

Post by Knibor »

Hi, I tried this script with an older script that you have written, but it isn't working.
I probably did something that is not right.

Code: Select all

local scriptVar = 'myCustomTimer'

return
{
    on =
    {
        timer =
        {
            'every minute',
        },

        customEvents =
        {
            scriptVar .. '*',  -- event triggered by emitEvent
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG, -- change to domoticz.LOG_ERROR when all is OK
       marker = scriptVar,
    },

    execute = function(dz, item)

        local every = 30 -- Frequency ==>>  the script should execute every nn seconds (min 1, max 30)

        if item.isCustomEvent then
            dz.log('Triggered by customEvent ' .. item.trigger, dz.log_DEBUG)
        else
            dz.log('Triggered by timer',dz.LOG_DEBUG)
            for i = every, (60 - every), every do
                dz.emitEvent(scriptVar .. ' after ' .. i .. ' seconds' ).afterSec(i)
            end
        end

        --[[

TWC control script based on surplus of own (solar) generated power.
 
the script uses for the TWC schedule function 3 variables
scheduledAmpEndTime en scheduledAmpStartTime   -- type time e.g. 23:00 and 07:00
activeScheduledDays -- type string e.g.  0,1,1,1,1,1,0 (In this example Sunday and Saturday off, other days On)

For control 4  virtual On/Off switches
TWC_Active          -- systeem active / Off
TWC_UserControlled  -- dzVents controlled       ==>> The script will ensure that UserControlled and Scheduler are mutual exclusive
TWC_Scheduler       -- TWC scheduler controle
TWC_fastload        -- set Amps fixed at maxAmp

and (optional) one setPoint device 
TWC_RestUsage      -- virtual Thermostat setpoint to have the possibility to have a variable level of restusage (amount to reserve for other incidental usage)

Input device is of type: P1 Smart meter 
Display device is type:  Electric (instant + counter)

versie 201905262100

]]--

local scriptVar = 'TWC'
return {
            on = { timer = {'every minute between sunrise and sunset', 'at 3:17'}, -- at 3:17 to reset to default
                   devices = {'TWC_*'},
                   httpResponse = { scriptVar .. '_callback'}
                 }, 

       logging = { level = domoticz.LOG_DEBUG,
                   marker = scriptVar },

        data    = { lastSendAmps = { initial = 6 },
                    lastSendScheduleTime = { initial = 0 },
                    fastloadSwitchedOn = { initial = 0 },
                    lastLogLine = { initial = "" },
                  },
        
    execute = function(dz, item)
        -- Your Changes below this line  
        local P1 = dz.devices('Power') -- Change to "name" or idx of your P1 meter
        local grid = dz.devices(33)  -- Change to "name" or idx of your (display) output device
        local usageDelivered = dz.devices(26) -- Change to "name" or idx of your usage delivered  
        
        local defaultAmp = 6           -- Start value
        local maxAmp = 16              -- Maximum load Amperage 
        local minAmp = 5               -- Minimum load Amperage
        local restUsage = 0            -- How much do you want to keep for own ( additional ) usage
        local urlTWC = '192.168.1.43'  -- IP or DNS of your TWC
        local fastloadMaxHours = 8     -- Max hours for fastload

        local debug2File = true        -- Ehh
        local debugFile = '/var/log/domoticz_debug.log'

        local schedule =   -- defaults for TWC internal scheduler  
        {
            scheduledAmpsMax = -1,             -- -1 is deactivate
            scheduledAmpsStartTime = '10:30',
            scheduledAmpsEndTime = '15:30',
            scheduledAmpsDay = {1,1,1,1,1,1,1,1}, -- All days 
            resumeTrackGreenEnergyTime = '-1:00', -- -1:00 is deactivate
        }

        -- No Changes required below this line  
        local userControlled = dz.devices('TWC_UserControlled')
        local scheduleControlled = dz.devices('TWC_Scheduler')
        local activeDevice = dz.devices('TWC_Active')
        local fastloadDevice = dz.devices('TWC_fastload')
        if dz.devices('TWC_RestUsage') then restUsage = dz.devices('TWC_RestUsage').setPoint end

        local isActive = activeDevice.state == 'On'
        local isDisabled = not isActive
        local isUserControlled = isActive and userControlled.state == 'On' 
        local isSchedulerControlled = isActive and ( not userControlled ) and scheduleControlled.state == 'On'   
        local toGrid = usageDelivered.WhActual

        local function logWrite2File(str)
            out = io.open(debugFile,'a')
            local origin = 'timer'
            if item.isDevice then origin = item.name elseif item.isHTTPResponse then origin = 'Response' end
            out:write(origin .. ":" .. dz.time.rawDate .. ' - ' ..dz.time.rawTime .. ' ; ' .. str .. "\n")
            out:close()
        end

        local function logWrite(str, level )
            dz.log(tostring(str), level or dz.LOG_DEBUG)
            if debug2File then
                if str ~= dz.data.lastLogLine then
                    logWrite2File("dzVents TWC: " .. str)
                    dz.data.lastLogLine = str
                end
            end
        end

        local function urlEncoded(url) -- not sure if we can't just use the dzVents std urlEncode method (to be checked)
            --This function converts only the special chars [,] and : to hex. Other chars are not touched
            local function char2Hex(c) -- internal helper function
                return string.format("%%%02X", string.byte(c))
            end

            if url == nil then return end

            url = url:gsub("\n", "\r\n") --convert Linefeed to Linefeed + return  
            url = url:gsub("[%[%]%:]", char2Hex) -- Convert [, ] and : to hexCode
            url = url:gsub(" ", "+") -- convert space to +
            return url
        end
        
        local function sendURL(amps, schedule)
           local TWCCommand = 
                        'scheduledAmpsMax=' .. schedule.scheduledAmpsMax ..             -- disable scheduled AmpsMax 
                        '&scheduledAmpStartTime='.. schedule.scheduledAmpsStartTime ..
                        '&scheduledAmpsEndTime=' .. schedule.scheduledAmpsEndTime ..-- only considered when scheduled AmpsMax active 
                        '&scheduledAmpsDay[0]=' .. schedule.scheduledAmpsDay[1] .. --Sunday
                        '&scheduledAmpsDay[1]=' .. schedule.scheduledAmpsDay[2] ..
                        '&scheduledAmpsDay[2]=' .. schedule.scheduledAmpsDay[3] ..
                        '&scheduledAmpsDay[3]=' .. schedule.scheduledAmpsDay[4] ..
                        '&scheduledAmpsDay[4]=' .. schedule.scheduledAmpsDay[5] ..
                        '&scheduledAmpsDay[5]=' .. schedule.scheduledAmpsDay[6] .. -- Friday
                        '&scheduledAmpsDay[6]=' .. schedule.scheduledAmpsDay[7] .. -- All days(only when scheduled AmpsMax active)
                        '&resumeTrackGreenEnergyTime=' .. schedule.resumeTrackGreenEnergyTime ..   -- (de)activate internal 
                        '&submit=Save' ..
                        '&nonScheduledAmpsMax=' .. amps            -- User controlled
           
           local url = 'http://'.. urlTWC .. '/index.php?' .. urlEncoded(TWCCommand)
           dz.openURL( { 
                            url = url,
                            method = 'GET',
                            callback = scriptVar .. '_callback',
                        })                      
            logWrite('url encoded send: ' .. url   )
        end
        
        local function toggleControlers(master) -- Make these switches mutual exclusive
logWrite("in function toggleControllers ")
            userControlled.opposite = scheduleControlled
            scheduleControlled.opposite = userControlled
            if master.active then 
                master.opposite.switchOff().checkFirst().silent()
            else
                master.opposite.switchOn().checkFirst().silent()
            end            
        end

        local function createSchedule(activeDays)
logWrite("in function createSchedule ")
            schedule.scheduledAmpsEndTime = dz.variables('scheduledAmpsEndTime').value
            schedule.scheduledAmpsStartTime = dz.variables('scheduledAmpsStartTime').value
            schedule.scheduledAmpsMax = maxAmp
            
            local days = dz.utils.stringSplit(activeDays,",")
            for i, v in ipairs(days) do
                schedule.scheduledAmpsDay[i] = v  
            end
        end

        local function controlURL(amps, schedule)
logWrite("in function controlURL ")
            sendURL(amps, schedule)
            dz.data.lastSendAmps = amps
        end

        local function controlFastload()
logWrite("in function controlFastload ")
            if item.active then 
                if dz.data.fastloadSwitchedOn == 0 then dz.data.fastloadSwitchedOn = dz.time.dDate end
                if dz.time.dDate < ( dz.data.fastloadSwitchedOn + fastloadMaxHours * 3600 ) then
                    fastloadDevice.switchOn().afterMin(10) -- trigger script every 10 minutes until switched Off
                    controlURL( maxAmp, schedule) -- Full power
                else
                    fastloadDevice.switchOff().silent()
                    dz.data.fastloadSwitchedOn = 0 
                end
            else
                fastloadDevice.cancelQueuedCommands() -- Switched off manual so prevent retriggering
            end
        end

logWrite("restUsage: " .. restUsage)
        if item.isDevice then
            logWrite("managing controler " .. item.name .. " is " .. item.state )
            if item == activeDevice and item.state == 'Off' then 
logWrite("in main 1 ")
                controlURL( 0, schedule)
                logWrite('Switched to inactive' )
            elseif item == fastloadDevice then 
logWrite("in main 2 ")
                activeDevice.switchOn().checkFirst().silent()
                controlFastload()
            elseif item == activeDevice then
logWrite("in main 3 ")
                toggleControlers(scheduleControlled)  -- When system is activated, it needs at least one control-type active   
            else
logWrite("in main 4 ")
                toggleControlers(item)                -- if userControlled is On then scheduleControlled must be off and vice versa 
            end
        elseif isDisabled then
            logWrite('inactive' )
        elseif item.isTimer and fastloadDevice.active  then
logWrite("in main 5 ")
            if fastloadDevice.lastUpdate.minutesAgo > 10 then controlURL( maxAmp, schedule) end -- Full power 
        elseif isSchedulerControlled and dz.data.lastSendScheduleTime == 0 then -- Only Send this once to set TWC to internal scheduler
logWrite("in main 6 ")
            logWrite("scheduler active")
            controlURL( maxAmp, createSchedule( dz.variables('activeScheduledDays').value ))
            dz.data.lastSendScheduleTime = dz.time.dDate
        elseif item.isTimer and (not scheduler) then
logWrite("in main 7 ")
            logWrite("timer active")
            dz.data.lastSendScheduleTime = 0 -- reset 
            if ( dz.time.hour < 4 ) or (not ( dz.data.lastSendAmps ) ) then  -- initialize or reset 
logWrite("in main 8 ")
                dz.data.lastSendAmps = defaultAmp
                return
            end 
            logWrite('Return to the grid: ' .. toGrid .. ' Watt' )
            grid.updateElectricity(toGrid)   -- update virtual sensor (display only)
            if toGrid > restUsage then -- we ( still ) have some spare
logWrite("in main 9 ")
                if dz.data.lastSendAmps < maxAmp then
logWrite("in main  10 ")

                    controlURL(math.min( dz.data.lastSendAmps + 1, maxAmp ), schedule)                 -- one step up
                end
            else  
logWrite("in main 11 ")
                if dz.data.lastSendAmps > minAmp then
logWrite("in main 12 ")
                    controlURL( math.max( dz.data.lastSendAmps - 1 , minAmp ), schedule)                 -- one step back
                end
            end
        elseif item.ok then                   -- return from TWC
logWrite("in main 13 ")
            logWrite("HTTP callback OK")
        elseif item.isHTTPResponse then       -- return was not OK !
logWrite("in main 14 ")
            local status = item.statusCode
            
            if item.protocol then -- available in dzVents >= 2.4.19
logWrite("in main 15 ")
                status = item.protocol .. ' (' .. status .. ') ' .. statusText 
            end
            logWrite('something went wrong with sending new amps to TWC. ( status: ' .. status .. ' )', dz.LOG_ERROR)
        end    
    end
}

    end
}
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: script on = {timer......

Post by waaren »

Knibor wrote: Monday 20 July 2020 13:32 Hi, I tried this script with an older script that you have written, but it isn't working.
I probably did something that is not right.
You merged the complete scripts and should only use the emitEvent and on customEvents parts.
This script is not well suited to be executed more frequent. It already executes multiple times a minute. Triggered by the timer and also by the response from the loader. If you try to use this every 30 seconds you will most likely get into situations where the script blocks other scripts or itself.

It would also become quite messy with lots of extra conditions to identify if it is triggered by a timer- or httpResponse- or custom event.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Knibor
Posts: 112
Joined: Sunday 20 May 2018 12:56
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: NL
Contact:

Re: script on = {timer......

Post by Knibor »

Thanks for the information, then the best way is "timer=every minute"
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest