User Tools

Site Tools


useful_programs

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
useful_programs [2023/10/05 12:12] – [Table functions] emozolyakuseful_programs [2024/03/19 09:39] (current) – [Detection of change of state] emozolyak
Line 155: Line 155:
  
 <code lua> <code lua>
 +-- converts bytes to integer value 
 +table.int = function(t) 
 +   local HEX_NUMBERING = 16
 +   return tonumber(table.hexStr(t), HEX_NUMBERING) 
 +end
 +
 +-- converts a table to hex view 
 +function table.hexStr(hextab, spacer) 
 +    local hex = {} 
 +    for _, hexbyte in ipairs(hextab) do 
 +        table.insert(hex, getHexByteAsStr(hexbyte))
 +    end 
 +    return table.concat(hex, spacer)
 +end 
 +
 +-- converts tab to bcd number 
 +table.bcd = function(t)
 +    local hex = table.hexStr(t)
 +    local out = tonumber(hex) 
 +    return out 
 +end 
 +
 +-- gets 2-char hex string from a byte 
 +function getHexByteAsStr(inputByte) 
 +    local strByte = string.format("%X", inputByte)    
 +    return (#strByte == 1 and '0' .. strByte) or strByte
 +end 
 +
 +
 +
 +-- reverses a table 
 +table.reverse = function (tab) 
 +    local outTable = {}
 +    for i = #tab, 1, -1 do 
 +        table.insert(outTable, tab[i])
 +    end 
 +    return outTable
 +end 
 +
 --[[  find an element in a table  --[[  find an element in a table 
     @ t - input table , v - value to find      @ t - input table , v - value to find 
Line 213: Line 252:
     return newTab      return newTab 
 end  end 
 +
 +--[[ convenient print function for tables 
 +@ t - table, indent - indent between key & value
 +--]] 
 +function tprint(t, indent)
 +    if not indent then indent = 0 end 
 +    for k, v in pairs(t) do 
 +        local formatting = string.rep(' ', indent) .. k .. ': '
 +        if type(v) == "table" then 
 +            ERROR(formatting) 
 +            tprint(v, indent + 1) -- recursive call 
 +        else
 +            if type(v) == "boolean" then 
 +                v = v and "TRUE" or "FALSE"
 +            end 
 +            ERROR(formatting .. v) 
 +        end 
 +    end 
 +end 
 +
 </code> </code>
  
Line 291: Line 350:
  
 <code lua> <code lua>
--- concats 2 tables processing boolean values  +--[[  universal print function 
-function myTabConcat(inputTable, separator) +      prints when global ENABLE_DEBUG is set  
-   for i, v in ipairs(inputTable) do  +    ... any list  
- if type(v) == 'boolean' then  +          if arguments have | symbol treats data as a 2-row data  
-    inputTable[i] = v and "true" or "false" +          "arg1arg2arg3 ... ", '|' 
- end  +          , arg1arg2, arg3 ...  
-   end  +          if arg type == table print all using tprint  
-   return table.concat(inputTable, separator) +          otherwise prints all arguments in a row  
-end  +--]] 
--- find an element in a table, return index or false if not found  +
-function table.find(inputTable, valueToFind) +
-    for i, tv in pairs(inputTable) do  +
-        if (tv == valueToFind) then  +
-            return i  +
-        end  +
-    end  +
-    return false  +
-end  +
--centers two strings of diff length  +
-function align2Strings(s1s2) +
-     local delta = #s1 - #s2 +
-     local absDelta = math.abs(delta) +
-     local prefix = string.rep(' 'math.floor(absDelta / 2) ) +
-     local suffix = prefix .. string.rep(' ',  absDelta % 2) +
-     if (delta > 0) then  +
-        s2 = prefix .. s2 .. suffix +
-     elseif (delta < 0) then   +
-        s1 prefix .. s1 .. suffix +
-     end  +
-     return s1, s2 +
-end  +
--- print a list of arguments with a header if '|' is provided +
 function DBG(...) function DBG(...)
-    if ENABLE_DEBUG then +     
 +    if (not ENABLE_DEBUGthen return end  
 +     
 +    -- piped printing 
  local pipePosition = table.find(arg, '|')  local pipePosition = table.find(arg, '|')
-        if (not pipePosition) then  +    if (pipePosition) then  
-            DEBUG(myTabConcat(arg, ' '))+        -- make header row  
 +        local th = {}  
 +        for word in string.gmatch(arg[1], "%S+") do  
 +    table.insert(th, word)  
 +        end  
 +        -- make data row  
 +     local td = table.sub(arg, pipePosition + 1, #arg) 
 +        if (#th ~= #td) then  
 +            ERROR('th & td in DBG are not equal!'; return 
         else          else 
-     if (pipePosition ~2) then  +            for i 1#th do  
- ERROR("Wrong pipe position in DBG!") ; return  +                local thltdl = string.len(th[i])string.len(td[i]
-     end  +                local diff math.abs(thl - tdl) 
-            local theadtdata = {}, {} +                if (thl tdl) then  
-            local valStartIndex, valEndIndexvalCurIndex 3, #arg, pipePosition  +                    td[i] = wrapToSpaces(td[i], diff)
-            for th in string.gmatch(arg[1], "%S+"do  +
- valCurIndex valCurIndex + 1  +
-                if (valCurIndex valEndIndex) then  +
-                    ERROR("Values row is shorter in DBG!"; return +
                 end                  end 
-                th, td align2Strings(th, tostring(arg[valCurIndex])+                if (tdl > thl) then  
-                table.insert(thead, th)  ; table.insert(tdata, td)  +                    th[i] wrapToSpaces(th[i], diff
-      end  +                end  
-      if (valCurIndex < valEndIndex) then  +            end  
- ERROR("thead row is shorter in DBG!") ; return  +            DEBUG(table.concat(th, ' ')) ; DEBUG(table.concat(td, ' '))
-      end  +
-      DEBUG(myTabConcat(thead, ' ') ) ; DEBUG(myTabConcat(tdata, ' ') )+
         end          end 
-    end +        return  
 +    end 
 +    -- table print  
 +    if table.some(arg, function (a) return type(a) == 'table' end ) then  
 +        tprint(arg) ; return  
 +    end   
 +    -- print in a row 
 +    DEBUG(table.concat(arg, ' ')) 
 end     end    
 +--[[ add extra spaces on both sides of string 
 +    @ s - string 
 +      n - number of spaces 
 +    --> string wrapped in spaces 
 +--]] 
 +function wrapToSpaces(s, n) 
 +    local spaces = string.rep(' ', math.floor(n / 2))
 +    return  spaces .. s 
 +            .. ((n % 2 == 0) and spaces or spaces .. ' ')
 +end 
 </code> </code>
 Then the print output can be enhanced like this: Then the print output can be enhanced like this:
Line 407: Line 465:
      
 end end
 +</code>
 +
 +<code lua>
 +-- converting utc timestamp in human readable string
 +function getDateString(utc)
 +    return os.date("%c", utc)
 +end 
 </code> </code>
  
Line 457: Line 522:
 ==== Simple TON timer ==== ==== Simple TON timer ====
 <code lua> <code lua>
--------------------------------- TON simple timer ----------------------------- +-- Timer constructor  
-TonClass = {} +Timer = {} ; setmetatable(Timer, {__call = function(self)  
-function TonClass :new() +                                       local obj = {stamp = os.time(), out = false
-    self.__index self  +                                       return setmetatable(obj{__index = self}
-    return setmetatable({stamp = os.time(), out = false,}, self)+                                   end }) 
 +-- Timer loop  
 +function Timer : run(in_delay)  
 +   local now = os.time()  
 +   if (not in_) then  
 +       self.out = false ; self.stamp = now  
 +   else  
 +       if (not self.out and (now - self.stamp>= delay) then  
 +           self.out = true  
 +       end  
 +   end  
 +   return self.out 
 end  end 
-  +function Timer reset() self.out = false ; self.stamp = os.time() end 
-function TonClass :__call(inputCondition, onDelay) +
-    local now = os.time() +
-    if (inputCondition ~= self.out) then  +
-        if (not inputCondition) then  +
-            self.out = false                               -- immediate off   +
-        else                 +
-            local timeDifference = now - self.stamp        -- check the time passed for the true condition  +
-            if (timeDifference < onDelay) then  +
-                DEBUG("going to sw on in " .. onDelay - timeDifference)   +
-                return self.out              +
-            else  +
-                self.out = true DEBUG("Switched on!"                       -- sw self on!   +
-            end  +
-        end  +
-    end  +
-  +
-    self.stamp = now  +
-    return self.out  +
-end -------------------------------- end of timer ------------------------------ +
- +
-function main (userId) +
-  local REQUIRED_DELAY = 15 -- seconds  +
-  if not TonTimer then  +
-      TonTimer = TonClass :new() +
-  end  +
-   +
-  DEBUG("ton state now = " .. tostring(TonTimer(true, REQUIRED_DELAY))) +
-   +
-end+
 </code> </code>
  
Line 613: Line 660:
    end     end 
        
 +end 
 +
 +</code>
 +
 +This one uses simper timer: 
 +<code lua>
 +include "timers"
 +CHAT_ID = 569335646
 +MSG_DELAY = 5 * 60 
 +
 +function main (userId)
 +  
 +  reportConnError(2, MSG_DELAY, CHAT_ID, 'CONN STUCK ON NODE https://node-name.webhmicloud.com')
 +  
 +end
 +
 +function reportConnError(connId, delay, chatId, msg)
 +    
 +    if (not tmr) then 
 +      tmr = Timer()
 +    end     
 +    
 +    if tmr : run(GetConnectionErrors(connId) > 0, delay) then 
 +        SendTelegramMessage(chatId, msg)    
 +        tmr : reset() 
 +    end 
 end  end 
  
Line 846: Line 919:
 Another way of creating objects:  Another way of creating objects: 
 <code lua> <code lua>
-ObjConstructor {} +TimerConstructor function ()  
-setmetatable(ObjConstructor, { +return setmetatable({}, { 
-             __call = function(self, delay)  -- init method  +        __call = function(self, delay)  
-                     local { +                local now os.time()  
-                     delay = delay   -- put init data here  +                if (not self.stamp or now - self.stamp >= delay) then  
-                    } +                    self.stamp = now  
-                     -- now may add methods to the prototype  +                    return true  
-                     return setmetatable(o, {__index = self})  +                else  
-                     end +                    return false  
-})+                end  
 +             end  
 +}) end   
  
-function ObjConstructor : oneShot() +-- usage   
-  + 
- local now = os.time() +function main (userId
-  +    --  creating timer    
- if (not self.stamp or (now - self.stamp >= self.delay)  then  +    if (not timer) then  
-     self.stamp now  +        timer TimerConstructor()
-     return true  +
-    else  +
-        return false +
     end      end 
          
 +    if timer (60) then 
 +        INFO('timer!')
 +        for i = 1, 8 do 
 +            toggle('synapse.do' .. i)
 +        end 
 +    end
 end end
  
-function main (userId+function toggle(v
-   +    W(v, 1 - R(v)) 
-  if (not tmr) then  +end 
-      local ONE_SHOT_DELAY = 10  +
-      tmr = ObjConstructor(ONE_SHOT_DELAY) +
-  end  +
-   +
-  DEBUG( tostring(tmr : oneShot() )  ) +
-   +
-end +
- +
 </code> </code>
  
Line 1445: Line 1515:
 ===== Detection of change of state ===== ===== Detection of change of state =====
  
-Sometimes you may need take actions upon changing any of the registers in a set. The following script's idea is to use one function to track changes of the respective registers, looking at their prevous value stored in a global structure (tablewhich is keeping between script execution+Sometimes you may need take actions upon changing any of the registers in a set. The following function returns true at the moment (scanthe value differs from previous value or false if no changes. Also, it can call callback function to make your code more readable.
  
 <code lua> <code lua>
-include "lib.lib"+OnChange = {} ; setmetatable(OnChange, {__call = function(self)  
 +                                    return function(v, cb)  
 +                                          local out = false  
 +                                          if (not self.prev) then 
 +                                              self.prev = v  
 +                                          end  
 +                                          if (self.prev and v ~= self.prev ) then  
 +                                              out = true  
 +                                              if cb then cb() end  
 +                                          end  
 +                                          self.prev = v  
 +                                          return out  
 +                                    end  
 +end  
 +})
  
 function main (userId) function main (userId)
------------------------- INIT (create globals) ---------------------   +  if (not onchange1) then  
-  if (not startedFlag) then   +      onchange1 OnChange()
-  +
-        detect = { curMinute = {regId = 1, prevValue = 0},  -- register's context  +
-                   stateReg  = {regId = 2, prevValue = 0}   -- which registes to track  +
-                 } +
-        mt = {__call = function(self, row)                  -- one method can detect as many registes as set in  +
-                           local me = self[row]             -- the detect table above  +
-                           local curValue = R(me.regId) +
- +
-                           if (not curValue) then return false end  +
-                            +
-                           local result  +
-                           if (not startedFlag) then  +
-                               me.prevValue = curValue ; result = false  +
-                           else  +
-                               if (R(me.regId) ~= me.prevValue) then  +
-                                   DEBUG("change of state detected for " .. row) +
-                                   me.prevValue = curValue ; result = true  +
-                               else  +
-                                   me.prevValue = curValue ; result =  false  +
-                               end  +
-                            end  +
-                            return result +
-                   end +
-           } +
-      setmetatable(detect, mt) +
-      prevAlerts #GetCurrentAlerts()   +
-      startedFlag = true  -- avoid this block further+
   end    end 
- ----------------------- MAIN ----------------------- 
-  
-     local alerts = GetCurrentAlerts()  
-     local alertCount = #alerts 
-      
-     if (alertCount > prevAlerts) or detect("curMinute") or detect("stateReg") then -- run on any of changes  
-         -- YOUR CODE FOR ACTIONS MIGHT BE HERE --  
-         local jsonToSend = cjson.encode({stateRegister = R(2), activeAlerts = (#alerts > 0) and 1 or 0}) 
-         AddInfoMessage(jsonToSend) 
-          
-         W(4, jsonToSend) -- to external register  
-         W(6, jsonToSend) -- to custom protocol 
-          
-     end  
-     
-     prevAlerts = alertCount 
      
 +  onchange1(R(110), function() INFO("true!") end )
 +    ------- Detecting changes of a set of registers ----------------
 +  local regSet = {{110, function() 
 +                            INFO("I'm a callback for reg 110")
 +                    end },
 +                   {1, function() 
 +                       INFO("I'm a callback for reg 1")
 +                    end }, 
 +                    {200, function() 
 +                        INFO("I'm a callback for reg 200")
 +                    end }, 
 +                 
 +   }
 +  
 +  local handlers = {} 
 +  
 +  -- registereing handlers 
 +  if (not handlers[regSet[1][1]]) then 
 +      for _, s in ipairs(regSet) do
 +          handlers[s[1]] = OnChange()
 +      end 
 +  end 
 +   
 +  -- using  handlers 
 +  for _, s in ipairs(regSet) do
 +      local reg, func   = s[1], s[2]
 +      handlers[reg](R(reg), func())    
 +  end 
 end end
 </code> </code>
Line 1516: Line 1585:
 INVALID_VALUE                = -100000 -- invalid value sign  INVALID_VALUE                = -100000 -- invalid value sign 
    
-filter = { {reg = 1, safeCopy = 2, errCount = 0},  -- what to filter  +filter = { {reg = 1, safeCopy = 2, errCount = 0},  -- reg - source register  
-           {reg = 3, safeCopy = 4, errCount = 0} } -- and where to store +           {reg = 3, safeCopy = 4, errCount = 0} } -- safeCopy - last read ok value 
    
 function main (userId) function main (userId)
useful_programs.1696507969.txt.gz · Last modified: 2023/10/05 12:12 by emozolyak

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki