Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


fibaroExtra


Recommended Posts

Posted (edited)

Here is a Lua file that can be added to any QuickApp and that provides missed functions, improvements, and nice-to-have add-ons.

(It's functions that I have factored out from my QuickerApp framework). 

It's backward compatible with the standard way to code a QA, so fibaroExtra functions can be introduced as needed in your code. Without using anything from fibaroExtra you get better error handling for setTimeout and json calls and some other beneath-the-surface enhancements (I thought about calling the file 'betterFibaro.lua'... :-) )

 

Please login or register to see this attachment.

 v0.923

 

Please login or register to see this attachment.

 

Here are some tutorials:

  • Please login or register to see this link.

    . If you need your QA to react to devices changing states or structure your own logic with user defined events.
  • Please login or register to see this link.

    . Allows QAs to exchange data without knowing each other's IDs - just agreeing what data (events) to exchange.
  • Please login or register to see this link.

    . Easier creating and loading of QuickAppChildren

 

Here is a "mini-installer". It will install the fibaroExtra file from my GitHub repository in the calling QA. It will do nothing if the file is already installed.

Please login or register to see this code.

 

Available functions:

Debug

  • function fibaro.debug(tag,...)                              -- Enhancements to existing fibaro.debug. See documentation
  • function fibaro.trace(tag,...) 
  • function fibaro.warning(tag,...)
  • function fibaro.error(tag,...)
  • function fibaro.debugf(tag,fmt,...)                       -- debug version with string.format arguments. See documentation
  • function fibaro.tracef(tag,fmt,...) 
  • function fibaro.warningf(tag,fmt,...) 
  • function fibaro.errorf(tag,fmt,...) 
  • fibaro.debugFlags.debugLevel = <number>       -- Supports user defined debug levels. See documentation
  • fibaro.debugFlags.traceLevel = <number>         -- Supports user defined debug levels. See documentation
  • fibaro.debugFlags.notifyWarning = <boolean>   -- Creates notifications in Notification Center for logged warnings
  • fibaro.debugFlags.notifyError = <boolean>         -- Creates notifications in Notification Center for logged errors
  • fibaro.debugFlags.onaction = <boolean>            -- Suppress onAction debug message
  • fibaro.debugFlags.uievent = <boolean>              -- Suppress UIEvent debug message
  • fibaro.debugFlags.json = <boolean>                   -- Converts tables to json in debug, print, and tostring functions.
  • fibaro.debugFlags.html = <boolean>                   -- Converts \n and <space> to </br> and &nbsp to make them visible in console log
  • fibaro.debugFlags.lateTimer = <number>           -- Warns if timers are run late
  • fibaro.debugFlags.reuseNotifies = <boolean>    -- Reuse entries in Notification Center for same messages

Scene functions

  • function fibaro.setSceneEnabled(sceneID,enabled)
  • function fibaro.isSceneEnabled(sceneID)
  • function fibaro.getSceneRunConfig(sceneID)
  • function fibaro.setSceneRunConfig(sceneID,runConfig)

Global variables

  • function fibaro.getAllGlobalVariables()                                  -- Returns list of all global variable names
  • function fibaro.createGlobalVariable(name,value,options)  -- Create a global variable
  • function fibaro.deleteGlobalVariable(name)                          -- Delete a global variable
  • function fibaro.existGlobalVariable(name)                             -- Check if a global variable exists
  • function fibaro.getGlobalVariableType(name)                      -- Get the type of a global variable
  • function fibaro.getGlobalVariableLastModified(name)        -- Get last time global variable was modified

Custom events

  • function fibaro.getAllCustomEvents()                                     -- Returns list of all custom events names
  • function fibaro.createCustomEvent(name,userDescription)  -- Create a custom Event
  • function fibaro.deleteCustomEvent(name)                              -- Delete a custom Event
  • function fibaro.existCustomEvent(name)                                 -- Check if a custom Event exists

Profile handling

  • function fibaro.activeProfile(id)
  • function fibaro.profileIdtoName(pid)
  • function fibaro.profileNameToId(name)

Alarm handling

  • function fibaro.partitionIdToName(pid)
  • function fibaro.partitionNameToId(name)
  • function fibaro.getBreachedDevicesInPartition(pid)
  • function fibaro.getAllPartitions()
  • function fibaro.getArmedPartitions()
  • function fibaro.getActivatedPartitions()
  • function fibaro.activatedPartitions(callback)                         -- Calls callback when a partition is activated (but not armed yet)
  • function fibaro.getBreachedPartitions()
  • function fibaro.getAlarmDevices()

Weather

  • function fibaro.weather.temperature()
  • function fibaro.weather.temperatureUnit()
  • function fibaro.weather.humidity()
  • function fibaro.weather.wind()
  • function fibaro.weather.weatherCondition()
  • function fibaro.weather.conditionCode()

SourceTrigger

  • function fibaro.registerSourceTriggerCallback(callback)
  • function fibaro.unregisterSourceTriggerCallback(callback)
  • function fibaro.enableSourceTriggers(trigger)
  • function fibaro.disableSourceTriggers(trigger)
  • function fibaro.sourceTriggerDelta(id,prop,value)
  • function fibaro._postSourceTrigger(trigger)

RefreshStates

  • function fibaro.registerRefreshStatesCallback(callback)
  • function fibaro.unregisterRefreshStatesCallback(callback)
  • function fibaro.enableRefreshStatesTypes(typs)
  • function fibaro.disableRefreshStatesTypes(typs)
  • function fibaro._postRefreshState(event)
  • fibaro._REFRESHSTATERATE = <number>

Time functions

  • function fibaro.toSeconds(str)                         -- Converts a "time string" to seconds. See doc.
  • function fibaro.between(start, stop[,time])     -- Check if time is between start and end time. 
  • function fibaro.midnight()                                  -- Return epoch at last midnight (start of current day)

QA related functions 

  • function fibaro.restartQA(id)
  • function fibaro.getQAVariable(id,name)

  • function fibaro.setQAVariable(id,name,value)

  • function fibaro.getAllQAVariables(id)

  • function fibaro.isQAEnabled(id)

  • function fibaro.enableQA(id,enable)

  • function fibaro.deleteFile(deviceId,file)
  • function fibaro.updateFile(deviceId,file,content)
  • function fibaro.updateFiles(deviceId,list)
  • function fibaro.createFile(deviceId,file,content)
  • function fibaro.getFile(deviceId,file)
  • function fibaro.getFiles(deviceId)
  • function fibaro.copyFileFromTo(fileName,deviceFrom,deviceTo)
  • function fibaro.addFileTo(fileContent,fileName,deviceId)
  • function fibaro.getFQA(deviceId) 
  • function fibaro.putFQA(content)

QuickApp class functions

  • function QuickApp:debug(...)                           -- Similar to fibaro.debug(...)
  • function QuickApp:trace(...)
  • function QuickApp:warning(...)
  • function QuickApp:error(...)
  • function QuickApp:debugf(...)
  • function QuickApp:tracef(...)
  • function QuickApp:warningf(...)
  • function QuickApp:errorf(...)
  • function QuickApp:debug2(tl,...)                      -- Similar to fibaro.debug(tag/level,...). Allows to set tag or debugLevel for log
  • function QuickApp:trace2(tl,...)
  • function QuickApp:warning2(tl,...)
  • function QuickApp:error2(tl,...)
  • function QuickApp:debugf2(tl,...)
  • function QuickApp:tracef2(tl,...)
  • function QuickApp:warningf2(tl,...)
  • function QuickApp:errorf2(tl,...)
  • function QuickApp:setView(elm,prop,fmt,...)           -- QuickApp:updateView but with string.format args
  • function QuickApp:getView(elm,prop)                      -- Get value of UI element
  • function QuickApp:setName(name)                          -- Change name of QA
  • function QuickApp:setIconMessage(msg,timeout)  -- Set the log field under the icon, can be removed after 'timeout' seconds.
  • function QuickApp:setEnabled(bool)                        -- Enable/disable the QA
  • function QuickApp:setVisible(bool)                           -- Set QA visible/invisible
  • function QuickApp:addInterfaces(interfaces)           -- Add interfaces to QA
  • function QuickApp:updateProperty(prop,value)       -- Update property. Will not update property not part of the device struct.
  • function QuickApp:createChild(args)
  • function QuickApp:loadChildren()
  • function QuickApp:setChildRemovedHook(fun)
  • function QuickApp:setChildIconPath(childId,path)
  • function QuickApp:callChildren(method,...)
  • function QuickApp:removeAllChildren()
  • function QuickApp:numberOfChildren()

Events

  • function fibaro.postRemote(id,ev)
  •  function fibaro.post(ev,t)
  • function fibaro.cancel(ref)
  • function fibaro.event(ev,fun,doc)
  • function fibaro.removeEvent(pattern,fun)
  • function fibaro.HTTPEvent(args)

Pub/Sub

  • function fibaro.publish(event)
  • function fibaro.subscribe(events[,handler])

Misc

  • function fibaro.trueFor(time, test,action)                                                   -- check if function returns true for a specified time and then call action
  • function fibaro.sequence(callSequence)                                                   -- call functions in sequence with optional delay in-between
  • function fibaro.stopSequence(ref)                                                            -- stops a started sequence
  • function fibaro.postGeofenceEvent(userId,locationId,geofenceAction) -- post a GeofenceEvent into the HC3 event mechanism

  • function fibaro.postCentralSceneEvent(keyId,keyAttribute)                   -- post a CentralSceneEvent into the HC3 event mechanism

  • function urlencode(str)
  • function fibaro.HC3version(version)    -- Returns or tests firmware version of HC3
  • function fibaro.getIPaddress(name)     -- Returns IP address of HC3
  • function netSync.HTTPClient(args)
  • function tostring(obj)                              -- Enhancements to existing tostring supporting .__tostring. See documentation.
  • function setTimeout(fun,ms)                  -- Enhancements to existing setTimeout. See documentation.
  • function setInterval(fun,ms)                   -- Enhancements to existing setInterval. See documentation.
  • function json.encode(tab)                      -- Better error message.
  • function json.encodeFast(tab)               -- Faster, more forgiving, and stable order, json.encode
  • function json.encodeFormated(tab)      -- formatted json encode
  • function json.decode(str)                       -- Better error message.

 

Utilities

  • function utils.copy(obj)                          -- copy table
  • function utils.copyShallow(obj)             -- copy table, first level only
  • function utils.map(f,list)                         -- apply function f to elements in list, returning new list of values
  • function utils.mapf(f,list)                       -- apply function f to elements in list, returning no value
  • function utils.reduce(f,list)
  • function utils.mapk(f,list)
  • function utils.mapkv(f,list)
  • function utils.size(t)                              -- returns size of table - works with key-value tables too
  • function utils.equal(o1,o2)                     -- check if 2 tables are equal
  • function utils.member(obj,list)             -- check if obj is a member of list
  • function utils.remove(obj,list)               -- remove obj from list
  • function utils.zip(f,...)
  • function utils.base64encode(string)                       -- base64 encode string
  • function utils.basicAuthorization(user,password)  -- create Authorization string "Basic "..utils.base64encode(user..":"..password)

 

Documentation:

 

Debugging


function fibaro.debug(tag,...)
  Replaces regular fibaro.debug but take debugFlags into account (see below)
  if the tag is a number, it will use the standard __TAG as tag and interpret
  the tag argument as a debug level.
  Usage:

Please login or register to see this code.


function fibaro.trace(tag,...) 
  Replaces regular fibaro.trace but take debugFlags into account (see below)
  if the tag is a number, it will use the standard __TAG as tag and interpret
  the tag argument as a debug level.
  Usage:

Please login or register to see this code.


function fibaro.warning(tag,...) 
  Replaces regular fibaro.warning but take debugFlags into account (see below)
  If fibaro.debugFlags.notifyWarning is true the log message will also be added to the notification center.
  
function fibaro.error(tag,...)
  Replaces regular fibaro.error but take debugFlags into account (see below)
  If fibaro.debugFlags.notifyError is true the log message will also be added to the notification center.
  
function fibaro.debugf(tag,fmt,...) 
  Replaces fibaro.debug but also formats the output the same way as string.format
  Usage:

Please login or register to see this code.


function fibaro.tracef(tag,fmt,...) 
  Works like fibaro.trace but also formats the output the same way as string.format
function fibaro.warningf(tag,fmt...)
  Works like fibaro.warning but also formats the output the same way as string.format
function fibaro.errorf(tag,fmt,...)
  Works like fibaro.error but also formats the output the same way as string.format
    
fibaro.debugFlags.debugLevel = <number>
  If nil will log all debug messages. If set to a number, will log all messages with a log level equal or lower to the number.
  
fibaro.debugFlags.traceLevel = <number>
  If nil will log all trace messages. If set to a number, will log all messages with a log level equal or lower to the number.
  
fibaro.debugFlags.notifyWarning = <boolean>
  If true will add the warning message to the notification center
  
fibaro.debugFlags.notifyError = <boolean>
  If true will add the error message to the notification center
  
fibaro.debugFlags.onaction = <boolean>
  If false will suppress the "onAction: " messages being logged. 
  
fibaro.debugFlags.uievent = <boolean>
  If false will suppress the "UIEvent: " messages being logged. 
  
fibaro.debugFlags.json = <boolean>
  If true will automatically json encode Lua tables in log messages (also when using 'tostring')
  Usage:

Please login or register to see this code.


fibaro.debugFlags.html = <boolean>
  If true will translate newline in logs to "</br>" and space to "&nbsp"
  
fibaro.debugFlags.reuseNotifies = <boolean>
  If true will reuse the same notification center entry for fibaro.error and fibaro.warning entries with the same message.
  This can be useful when the code will log multiple warnings/errors for the same reason.

 

Scene functions

 

function fibaro.isSceneEnabled(sceneID) 

  Return true if scene is enabled


function fibaro.setSceneEnabled(sceneID,enabled)
  Enables or disables a scene
  
function fibaro.getSceneRunConfig(sceneID)
  Gets the scenes runConfig parameter
  
function fibaro.setSceneRunConfig(sceneID,runConfig)
  Sets the scenes runConfig parameter

 

Global variables


function fibaro.getAllGlobalVariables()
  Returns a table with the names of all defined global variables
  
function fibaro.createGlobalVariable(name,value,options)
  Create a global variable.
  Usage:
  
function fibaro.deleteGlobalVariable(name)
  Deletes global variable
  
function fibaro.existGlobalVariable(name)
  Returns true if global variable exists
  
function fibaro.getGlobalVariableType(name)
  Returns the type of the global variable - isEnum and readOnly

  Usage:

Please login or register to see this code.


function fibaro.getGlobalVariableLastModified(name)
  Returns time when global was last modified

  Usage:

Please login or register to see this code.

 

Custom events


function fibaro.createCustomEvent(name,userDescription)
  Creates a customEvent
  Usage:

Please login or register to see this code.


function fibaro.deleteCustomEvent(name)
  Deletes a customEvent
  Usage:

Please login or register to see this code.

 
function fibaro.existCustomEvent(name)
  Returns true of customEvent exists
  Usage:

Please login or register to see this code.

 

function fibaro.getAllCustomEvents()
  Returns table with names of all defined customEvents

Please login or register to see this code.

 

Profile handling

 

function fibaro.activeProfile(id)

  If id is nil returns active profile. Otherwise sets profile to id (id can also be name <string> of profile)

 

function fibaro.profileIdtoName(pid)

  Returns profile name given id

 

function fibaro.profileNameToId(name)

  Returns profile id given name

 

Alarm handling


function fibaro.partitionIdToName(pid)
  Return the name of alarm partition with id 'pid'
  Usage:

Please login or register to see this code.


function fibaro.partitionNameToId(name)
  Return the id of alarm partition with name 'name'
  Usage:

Please login or register to see this code.


function fibaro.getBreachedDevicesInPartition(pid)
  Returns a table with ids of devices breached in partition
  Usage:

Please login or register to see this code.

 

function fibaro.getAllPartitions()
  Returns a table with ids of all alarm partitions
  
function fibaro.getArmedPartitions()
  Returns a table with ids of all alarm partitions that are armed
  Usage:

Please login or register to see this code.


function fibaro.getActivatedPartitions()
  Returns a table partitions that are activated but not yet armed (delay)
  Usage:

Please login or register to see this code.


function fibaro.activatedPartitions(callback)
  Calls callback with partition that becomes activated.

  When given a callback function it starts a loop that checks the partitions every second.

  If the function is called with nil as callback the loop will be paused.
  Usage:

Please login or register to see this code.

 

function fibaro.getBreachedPartitions()
  Returns a table with ids of all alarm partitions that have breached devices
  Usage:

Please login or register to see this code.


function fibaro.getAlarmDevices()
  Returns a table of devices that can be part of an alarm partition.
  Usage:

Please login or register to see this code.

 

Weather

 

function fibaro.weather.temperature()

Usage:


function fibaro.weather.temperatureUnit()

Usage:


function fibaro.weather.humidity()

Usage:


function fibaro.weather.wind()

Usage:


function fibaro.weather.weatherCondition()

Usage:


function fibaro.weather.conditionCode()

Usage:

 

SourceTrigger

 

function fibaro.getSourceTriggers(callback)
  Register a callback to get sourceTriggers.
  By default 'device','alarm','global-variable','custom-event' are enabled (see fibaro.enableSourceTriggers() below)

  When this is called with a callback function a loop that checks the /api/refreshStates every second is started.

  If called with nil as callback, it will pause the loop.

  Usage:
 

Please login or register to see this code.


  Available sourceTrigger types are:

Please login or register to see this code.


function fibaro.enableSourceTriggers(trigger)
  Enabled sourceTrigger types to be reported. This gives the possibility to filter out relevant events.
  Usage:

Please login or register to see this code.


function fibaro.disableSourceTriggers(trigger)
  Disable sourceTrigger types to be reported.  This gives the possibility to filter out relevant events.
  Usage:

Please login or register to see this code.


function fibaro.sourceTriggerDelta(id,prop,value)
  For a device with a numeric property, sets a threshold how much the value have to change before it will trigger a callback
  Can be useful for "noisy" properties that reports many small changes.
  Usage:

Please login or register to see this code.


function fibaro._postSourceTrigger(trigger)
  Posts a "fake" sourceTrigger to the fibaro.getSourceTrigger logic.
  Can be useful for debugging:
  Usage:

Please login or register to see this code.

 

RefreshStates


function fibaro.getRefreshStates(callback)
  Register a callback to get all events returned from /refreshStates

  When this is called with a callback function a loop that checks the /api/refreshStates every second is started.

  If called with nil as callback, it will pause the loop.

  Ex.

Please login or register to see this code.

  
function fibaro.enableRefreshStatesTypes(typs)
  By default all event types are enabled and reported to the callback given to fibaro.getRefreshStates(callback)
  This allows event types that have been disabled to be enabled
  Usage:

Please login or register to see this code.

 

function fibaro.disableRefreshStatesTypes(typs)
  By default all event types are enabled and reported to the callback given to fibaro.getRefreshStates(callback)
  This allows event types to be disabled and not reported to the callback, simple type of filtering.
  Usage:

Please login or register to see this code.


function fibaro._postRefreshState(event)
  This allows an event to be posted to the fibaro.getRefreshStates routine.
  Can be useful for debugging.
  Usage:

Please login or register to see this code.

 

fibaro._REFRESHSTATERATE = <number>

 defaults to 1000 and is the interval in ms that the refreshState loop polls for new events.

 

Time functions

 

fibaro.toSeconds(string)
Converts a string of type "10:00"  or "10:00:00" to seconds.
Supports +/- offset.  Ex. "10:00+10"
Supports to get time string from fibaro global. Ex. "$Wakeup+60"
Supports sunset/sunrise. Ex. "sunset+300"

 

fibaro.between(start, stop,time). 
Tests if time is between start and stop. Time can be specified with fibaro.toSeconds strings.
Usage;

Please login or register to see this code.

 

QA functions

 

function fibaro.restartQA(id)

  Restarts QA with id. If id is nil, restarts current QA

 

function fibaro.getQAVariable(id,name)

  Get quickAppVariable from QA with id. If id is nil, get from current QA

 

function fibaro.setQAVariable(id,name,value)

   Set quickAppVariable from QA with id. If id is nil, set current QA

 

function fibaro.getAllQAVariables(id)

   Returns a key-value table with all quickAppVariables of QA with id.

 

function fibaro.isQAEnabled(id)

   Returns true if QA is enabled

 

function fibaro.enableQA(id,enable)

   Sets the enabled state of QA (true or false)

 

function QuickApp:debug(...)                           

function QuickApp:trace(...)

function QuickApp:warning(...)

function QuickApp:error(...)

function QuickApp:debugf(...)

function QuickApp:tracef(...)

function QuickApp:warningf(...)

function QuickApp:errorf(...)
Similar to fibaro.debug(...) et.al.
 

function QuickApp:debug2(tl,...)       

function QuickApp:trace2(tl,...)

function QuickApp:warning2(tl,...)

function QuickApp:error2(tl,...)

function QuickApp:debugf2(tl,...)

function QuickApp:tracef2(tl,...)

function QuickApp:warningf2(tl,...)

function QuickApp:errorf2(tl,...)

Similar to fibaro.debug(tag/level,...). Allows to set tag or debugLevel for log

 

function QuickApp:setView(elm,prop,fmt,...)
QuickApp:updateView but with string.format args

 

function QuickApp:getView(elm,prop)
Get value of UI element

 

function QuickApp:setName(name)
Change name of QA

 

function QuickApp:setIconMessage(msg,timeout)
Set the log field under the icon, can be removed after 'timeout' seconds.

 

function QuickApp:setEnabled(bool)
Enable/disable the QA

 

function QuickApp:setVisible(bool)
Set QA visible/invisible

 

function QuickApp:addInterfaces(interfaces)
Add interfaces to QA

 

function QuickApp:updateProperty(prop,value)
Update property. Will not update property not part of the device struct.

 

function QuickApp:createChild(args)

...

 

function QuickApp:loadChildren()

...

 

function QuickApp:setChildRemovedHook(fun)

...

 

function QuickApp:setChildIconPath(childId,path)

...

 

function QuickApp:callChildren(method,...)

...

 

function QuickApp:removeAllChildren()

...

 

function QuickApp:numberOfChildren()

...

 

Pub/Sub

This provides an efficient publish subscribe mechanism for events. An event is a Lua table with a type key (like sourceTriggers)

 

function fibaro.subscribe(patterns[,handler])

Subscribes to events matching patterns. patterns can be a single pattern or a list of patterns

Usage:

Please login or register to see this code.

Instead of defining the event handler explicitly we can provide it directly in the subscription command.

Please login or register to see this code.

 

function fibaro.publish(event)

Publish an event to all QAs that have subscribed to the event.

Usage:

Please login or register to see this code.

 

Misc

 

fibaro.FIBARO_EXTRA

  (string). version of fibaroExtra.lua functions. 

 

function urlencode(str)
  urlencodes a string. urldecode(str) is available by default in a QA context, but urlencode is missing.
  Usage:

Please login or register to see this code.

 

function fibaro.HC3version(version)
  Returns the version of the firmware installed on the HC3. If a version argument is given the function returns a boolean, true or false,  if the current version is higher or equal to the given argument
  Usage:

Please login or register to see this code.


function fibaro.getIPaddress(name)
  Returns the IP address of first enabled interface of the HC3 found.
  If argument name is given return the IP address of the first enabled interface matching name.
  Usage:

Please login or register to see this code.

 

function netSync.HTTPClient(args)
  Works like net.HTTPClient() but only run one request at the time. Additional requests are queued up and are allowed to run when the current request has completed. This is useful when polling devices so that they don't get overrun with requests if they are a bit slow to respond. Ex. the Philips Hue hub usually don't like to many parallel incoming requests...

 

function tostring(obj)
  Like Lua tostring but if fibaro.debugFlags.json is true will convert Lua tables to a string with json.encodeFast.
  Also, if the object is a Lua table and has a key .__tostring bound to a function it will use that function to convert the table to a string.
  Usage:

Please login or register to see this code.


function setTimeout(fun,ms[,tag])
  Replaces regular setTimeout but protects fun with pcall and report error messages.
  It also allows for ms to be larger then 2147483648-1 (32 days)

  The reference returned can be printed out and will tell what time the timer expires.

  A third argument (tag) will be used in the log as an optional identifier.
 

Please login or register to see this code.

A new flags, fibaro.debugFlags.lateTimer. If set to a number X will log a warning message if timer is run more then X seconds late.
 

Please login or register to see this code.


function setInterval(fun,ms)
  Replaces regular setInterval but protects fun with pcall and report error messages.
  It also allows for ms to be larger then 2147483648-1 (32 days)
    
function json.encode(tab)
  Replaces regular json.encode but with better error message (not deep inside json.encode)
  
function json.encodeFast(tab)
  Replaces regular json.encode but faster and don't throw errors on functions and userdata

  Usage:

Please login or register to see this code.


  
function json.encodeFormated(tab)
  Like json.encodeFast but formated with newlines and tabs.

  Usage:

Please login or register to see this code.

 

function json.decode(str)
  Replaces regular json.decode but with better error message (not deep inside json.encode)

 

function fibaro.postGeofenceEvent(userId,locationId,geofenceAction)

 post a GeofenceEvent into the HC3 event mechanism

 

function fibaro.postCentralSceneEvent(keyId,keyAttribute)

 post a CentralSceneEvent into the HC3 event mechanism

  

fibaro.trueFor(time, test,action)
Test if function test is true for time seconds and if so calls actions.
Usage:
 

Please login or register to see this code.

 

fibaro.sequence(seq)
Will call functions in sequence with optional delay.

Usage:

Please login or register to see this code.

 

fibaro.stopSequence(seq)
Will stop started sequence 

Usage:

Please login or register to see this code.

 

Utilities

These functions are available in the "namespace" utils.*


function utils.copy(obj)
  Copies a Lua table
  
function utils.copyShallow(obj)
  Copies the first "level" of Lua table - faster than copy.
  
function utils.map(f,list)
  Applies function f on all elements in list and returns a new list

  Usage:

Please login or register to see this code.


function utils.mapf(f,list)
  Applies function f on all elements in list but don't return a result. Faster than map

Please login or register to see this code.


function utils.reduce(f,list)
  ...


function utils.mapk(f,list)

  ...
  
function utils.mapkv(f,list)
  ...


function utils.equal(o1,o2)
  Check if two Lua objects are equals, including tables


function utils.member(obj,list)
   Check if object is member of list


function utils.remove(obj,list)
    Remove object from list


function utils.zip(f,...)
   ...


function utils.base64encode(string)
  Encodes string with base64 encoder
  
function utils.basicAuthorization(user,password)
  Creates a basicAuthorization string suitable for HTTP authentication.
  Usage:
    
 

Tests and examples:

 

A test example:

Please login or register to see this spoiler.

 

Edited by jgab
  • Like 5
  • Thanks 10
Link to comment
Share on other sites

  • Topic Author
  • Posted (edited)

    v 0.7 of the file.

    New:

    • fibaro._REFRESHSTATERATE to control the refreshState poll interval. Defaults to 1000
    • setTimeout now returns a reference that can be printed out and show what time the timer expires.
      Ex.

      Please login or register to see this code.

      It also allows a debug tag to be added as the 3rd argument to setTimeout.
      A new flags, fibaro.debugFlags.lateTimer. If set to a number X will log a warning message if timer is run more then X seconds late.
      Ex.

      Please login or register to see this code.

      Lastly, all timers are assigned a number starting with 1.
      If you rely heavily on timers in your code this is very valuable when debugging.

    • fibaro.toSeconds(string).
      Converts a string of type "10:00"  or "10:00:00" to seconds.
      Supports +/- offset.  Ex. "10:00+10"
      Supports to get time string from fibaro global. Ex. "$Wakeup+60"
      Supports sunset/sunrise. Ex. "sunset+300"

    • fibaro.between(start, stop,time). 
      Tests if time is between start and stop. Time can be specified with fibaro.toSeconds strings.
      Ex.
      fibaro.between("sunset+300","sunrise-300")
      fibaro.between("sunset+300","sunset-300","22:00")

    • fibaro.trueFor(time, test,action).
      Test if function test is true for time seconds and if so calls actions.
      Ex.
       

      Please login or register to see this code.

     

    • fibaro.sequence(seq).
      Will call functions in sequence with optional delay.
      Ex.
      fibaro.sequence({{fibaro.call,"turnOn"},1000,{fibaro.call,"turnOff"}})
    Edited by jgab
    • Thanks 1
    Link to comment
    Share on other sites

  • Topic Author
  • Added v0.8 with some more QA related functions (additions to the class)

    • Like 2
    • Thanks 2
    Link to comment
    Share on other sites

  • Topic Author
  • v.902

    • pub/sub support
    • Lua event handler
    • QA child management
    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)

    The event system supported by fibaroExtra has 3 levels.

     

    Please login or register to see this image.

    /monthly_2021_07/layers.png.19435943d1287e3c3f0bfec339e165ce.png" />

     

    1. We can register callbacks for the /refreshStates API. Instead of writing our own loop to poll the /refreshStates API we can do:

    Please login or register to see this code.

    The advantage here is that our handler function gets called whenever there is an event available. We get all events that the HC3 emits.

    The drawback is that we have to code a bit to decipher the event. In the example above we look if device 88 is breached.

     

    2. Next level we can register for 'sourceTriggers'. It's a similar format as for scenes but support some more types.

    Please login or register to see this code.

    The advantage is that the events are a bit higher level. Less useful events are filtered away. 

    The disadvantage is that we still need to do a lot of tests to find the triggers we are interested in.

     

    3. We can step up another level and register callbacks for events that match templates that we provide.

    Please login or register to see this code.

     

    Instead of defining one callback for all sourceTriggers, we register multiple event handlers and give them templates that if they match it will call the provided function.

    The template can be partial

    Please login or register to see this code.

    This will match events from all devices who has a value property set to true

    Actually device triggers are a bit special and we can do

    Please login or register to see this code.

    This will match device 88,99 or 101 if their value property change. 

     

    The templates are "compiled" and put in hash tables so the lookup of the correct handler to call for an incoming trigger is very fast.

     

    Templates also allow us to put constraints on value. Assume the device above where multilevels so the values where numbers.

    If want to only match if a device is on, e.g. it's value is > 0 we can do

    Please login or register to see this code.

     

    So here we have a way to write handlers that matches incoming sourceTriggers. The cool thing is that we can post our own triggers (or events).

    As long as they are a Lua table with a 'type' key they are events and we can post them.

    Please login or register to see this code.

    The handler will match event 'myEvent' and the handler will be called.

     

    The fibaro.post function can take an optional time in the future when the event should be posted. The time is usually expressed in a 'time string'

    +/HH:HH[:SS]  posts the event after the given time

    t/HH:HH[:SS]  posts the event at the given time this day. If the time has already passed the event is not posted

    n/HH:HH[:SS]  posts the event at the given time, or if the time has passed, the given time next day

     

    Please login or register to see this code.

    The time argument can also be a number and then the rule is that if it's < os.time() then it interpreted as seconds from now. If its >= os.time() then it's interpreted as absolute time.

    So if we want to post an event for New Years eve 2022 we can do

    Please login or register to see this code.

     

    This way we can easily do a 5s loop

    Please login or register to see this code.

    In fact the event handler we give for myLoop is not really aware of the time interval that should be used - it just uses the time value provided in the event and that we gave when we posted the initial event to get it starting.


     

    Please login or register to see this code.

    This starts 4 loops that run in "parallel" on different time intervals.

     

    The HC3 is an asynchronous systems, triggers can arrive at any time. By structuring our programs using events and integrating HC3 events with our own application events we can get robust and well structured programs.

     

    ...and we can easily make QAs communicate with events too.

     

    If one QA with the id 555 has the event handler

    Please login or register to see this code.

     

    Another QA can do

    Please login or register to see this code.

    and it will be sent to QA 555 and it's event handler will be triggered.

    postRemote will add an extra field ._from with the posting QA's deviceID. That is a way to see if it's an "external" event from another QA and can also be used to reply to the sender.

     

    One more thing. The picture in the beginning shows the QuickApp posting to all 3 layers. Posting at the top layer we have talked about as it supports posting user defined event. However, it's also possible to post sourceTrigger or refreshState events. The latter can be useful when debugging to see if your code reacts to sourceTriggers the correct way - much easier than waiting for the  real trigger or having to ask your wife to open the bathroom door to trigger the sensor... ;-) 

     

    ...more to come...

     

     

     

    Edited by jgab
    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)

    The

    Please login or register to see this link.

    talked about the event system in fibaroExtra and can be good to revisit to understand what events are.

     

    We could send events to other QAs by using

    Please login or register to see this code.

    and the other QA could have a handler to receive the event and print out the greeting.

    Please login or register to see this code.

     

    The drawback is that the sender needs to know the ID of the receiving QA. We can make it a bit easier by looking up the QA by name

    Please login or register to see this code.

    ...but we would like to get around that.

     

    The publish/subscribe mechanism in fibaroExtra allow us to do exact that.

    A 'subscriber' tells what kind of events it would like to receive (like we do with a fibaro.event template)

    Please login or register to see this code.

    This tells the system that all QAs that publish an event that matches this will be sent to this QA.

     

    To publish something is simple.

    Please login or register to see this code.

    It's like a fibaro.post() but it will be sent to every subscriber

     

    So how does the subscriber get the event? By defining a handler.

    Please login or register to see this code.

     

    The nice thing here is that QAs don't need to know each other's IDs. They just need to agree about what data (events) to exchange.

    This is another piece in making the HA system robust.

     

    There is a lot of optimisations under the surface. The QAs exchange subscriptions with each other so when the time comes to publish an event the event is only sent to QAs that subscribe to the event (source filtering). It also leverage the event matching mechanism to efficiently find what QA subscribes to what event.

    Edited by jgab
    • Thanks 1
    Link to comment
    Share on other sites

    Jan,

    Is this something to replace post and remote?

    I like the thinghy for not using QA ID so if reload QA or take a fresh ER4 you dont need to adapt QA numbers.

    Please advice,

    //Sjakie

    Link to comment
    Share on other sites

  • Topic Author
  • 3 hours ago, Sjakie said:

    Jan,

    Is this something to replace post and remote?

    I like the thinghy for not using QA ID so if reload QA or take a fresh ER4 you dont need to adapt QA numbers.

    Please advice,

    //Sjakie

    The same public/subscribe is available in ER4 and is compatible with fibaroExtra.

    I will switch ER4 to use the fibaroExtra library soon.

    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)

    fibaroExtra makes it easier to deal with QuickAppChildren.

     

    With the standard functions we are given we need to work a bit when we create and load children as they need to be mapped to the classes used when instantiating them.

    fibaroExtra's QuickAppChild functions automates a lot of this.

    The functions we have are

    • function QuickApp:createChild(args)                       -- Create a child QA
    • function QuickApp:loadChildren()                            -- Load existing children at startup
    • function QuickApp:setChildRemovedHook(fun)      -- Register callback when user deletes child QA
    • function QuickApp:setChildIconPath(childId,path) -- Set child icon
    • function QuickApp:callChildren(method,...)             -- Call a function/method on all children
    • function QuickApp:removeAllChildren()                   -- Delete all children
    • function QuickApp:numberOfChildren()                   -- Return the number of children

     

    self:loadChildren() will load existing children. Everything needed to restore the children is stored in the child QA (like class) so a simple call to self:loadChildren() will do. The function will also return the number of children loaded.

     

    self:createChild() is doing most of the job.

     

    self:createChild{

       type = <fibaro type>,

       name = <Child QA name>,

       className = <QuickAppChild class name for this child>,

       quickVars = <key-value table>,       -- quickAppVariables we want to initialise the child with

       properties = <key-value table>,     -- optional properties we want to set   

       interfaces = <key-value table>,     -- optional interfaces we want to add

    }

     

    It returns the child object if successful. The child object will have the .id property with the QA deviceID it got assigned.

     

    Here is a minimalistic, functional , example of Philips Hue QuickAppChildren. Only maps lights as binarySwitches in this example.

     

    Please login or register to see this code.

     

    Edited by jgab
    • Like 1
    Link to comment
    Share on other sites

    • 3 weeks later...
  • Topic Author
  • Posted (edited)

    Here is an example of a common task that is easy to achieve with the helper functions from fibaroExtra.

     

    The task at hand is to run a sequence of commands at a certain time every day - in this case to turn on and off sprinklers in a given sequence at a specific time during the day.

     

    First we need to run something at a given time during the day. The fibaroExtra event mechanism is perfect for that.

    Please login or register to see this code.

    What we do here is that we create an "event loop". 

    We create an event handler that listen to the 'runIrrigation' event and in the handler function for that event handler we re-post the event at the next time we want to get the event. The post command takes an optional second argument that is the time in the future the event should be posted.

    Time can be expressed as "time strings". "n/15:00" specifies the next upcoming 15:00. If the current time is before 15:00 it will be 15:00 today. If the current time (when we post) is after 15:00, it will be 15:00 the next day.

    Other formats are

    "+/15:00", meaning 15 hours from now - not what we want in this case.

    "t/15:00", meaning 15:00 today, if we passed the time the event will not be posted

    <small number>, seconds from now. If the number is smaller than os.time() it will be seconds from now

    <large number>, absolute time in epoch. If the number is larger than os.time() it will be considered the time in epoch to post the event. 

     

    The advantage with the event model is that we can post many different events and they will run in "parallel"...  The other advantage is that we don't drift, it will run at 15:00 exactly, every day...

     

    Anyway, at 15:00 we want to do stuff, in this case turning on and off sprinklers with a wait period. In a QA we can't really use fibaro.sleep as it blocks other interactions within the QA, so we usually use setTimeout.

     

    Here fibaroExtra has a convenient function 

    fibaro.sequence(....) 

    that runs commands with option delays using a setTimeout loop for us.

    The arguments are either a number being the delay (in ms) or a table {<function>,<arg1>,<arg2>,...} and the function will be called with the given arguments.

    Ex.

    fibaro.sequence({fibaro.call,88,'turnOn'},5*60*1000,{fibaro.call,88,'turnOff'})

    will call turnOff on device 88, wait for 5min and then call turnOff on the same device.

     

    In our example we want to turn on and off sprinklers.

    Please login or register to see this code.

     

    If we put it all together we get

    Please login or register to see this code.

     

    Compact, extensible, and easy to maintain code.

    Edited by jgab
    • Thanks 1
    Link to comment
    Share on other sites

    57 minutes ago, jgab said:

    Here is an example of a common task that is easy to achieve with the helper functions from fibaroExtra.

     

    The task at hand is to run a sequence of commands at a certain time every day - in this case to turn on and off sprinklers in a given sequence at a specific time during the day.

     

    First we need to run something at a given time during the day. The fibaroExtra event mechanism is perfect for that.

    Please login or register to see this code.

    What we do here is that we create an "event loop". 

    We create an event handler that listen to the 'runIrrigation' event and in the handler function for that event handler we re-post the event at the next time we want to get the event. The post command takes an optional second argument that is the time in the future the event should be posted.

    Time can be expressed as "time strings". "n/15:00" specifies the next upcoming 15:00. If the current time is before 15:00 it will be 15:00 today. If the current time (when we post) is after 15:00, it will be 15:00 the next day.

    Other formats are

    "+/15:00", meaning 15 hours from now - not what we want in this case.

    "t/15:00", meaning 15:00 today, if we passed the time the event will not be posted

    <small number>, seconds from now. If the number is smaller than os.time() it will be seconds from now

    <large number>, absolute time in epoch. If the number is larger than os.time() it will be considered the time in epoch to post the event. 

     

    The advantage with the event model is that we can post many different events and they will run in "parallel"...  The other advantage is that we don't drift, it will run at 15:00 exactly, every day...

     

    Anyway, at 15:00 we want to do stuff, in this case turning on and off sprinklers with a wait period. In a QA we can't really use fibaro.sleep as it blocks other interactions within the QA, so we usually use setTimeout.

     

    Here fibaroExtra has a convenient function 

    fibaro.sequence(....) 

    that runs commands with option delays using a setTimeout loop for us.

    The arguments are either a number being the delay (in ms) or a table {<function>,<arg1>,<arg2>,...} and the function will be called with the given arguments.

    Ex.

    fibaro.sequence({fibaro.call,88,'turnOn'},5*60*1000,{fibaro.call,88,'turnOff'})

    will call turnOff on device 88, wait for 5min and then call turnOff on the same device.

     

    In our example we want to turn on and off sprinklers.

    Please login or register to see this code.

     

    If we put it all together we get

    Please login or register to see this code.

     

    Compact, extensible, and easy to maintain code.

     

    Thanks a lot...just a side question...If we forexample run multiple settimouts all the day, doesn't it burden too heavily the system? Can it be used safely, or its'not recommended?

    Link to comment
    Share on other sites

  • Topic Author
  • 12 minutes ago, Neo Andersson said:

     

    Thanks a lot...just a side question...If we forexample run multiple settimouts all the day, doesn't it burden too heavily the system? Can it be used safely, or its'not recommended?

    No, setTimeouts don't take cpu time when they don't run (the event/post and sequence mechanism in fibaroExtra uses setTimeout). 

    In my EventRunner framework I run hundreds of timers in parallel without impact.

    23 minutes ago, Neo Andersson said:

    Hey, i was looking for a solution, as i described above...

    What a coincidence :-) 

    • Like 1
    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)

    The previous example used events and sequence to carry out the task.

    It turn out that post can also post a function (not only events). With the new fibaroExtra v0.920 we can make the example more... compact.

    Please login or register to see this code.

     

    Edited by jgab
    Link to comment
    Share on other sites

    3 hours ago, jgab said:

    Here is an example of a common task that is easy to achieve with the helper functions from fibaroExtra.

     

    The task at hand is to run a sequence of commands at a certain time every day - in this case to turn on and off sprinklers in a given sequence at a specific time during the day.

     

    First we need to run something at a given time during the day. The fibaroExtra event mechanism is perfect for that.

    Please login or register to see this code.

    What we do here is that we create an "event loop". 

    We create an event handler that listen to the 'runIrrigation' event and in the handler function for that event handler we re-post the event at the next time we want to get the event. The post command takes an optional second argument that is the time in the future the event should be posted.

    Time can be expressed as "time strings". "n/15:00" specifies the next upcoming 15:00. If the current time is before 15:00 it will be 15:00 today. If the current time (when we post) is after 15:00, it will be 15:00 the next day.

    Other formats are

    "+/15:00", meaning 15 hours from now - not what we want in this case.

    "t/15:00", meaning 15:00 today, if we passed the time the event will not be posted

    <small number>, seconds from now. If the number is smaller than os.time() it will be seconds from now

    <large number>, absolute time in epoch. If the number is larger than os.time() it will be considered the time in epoch to post the event. 

     

    The advantage with the event model is that we can post many different events and they will run in "parallel"...  The other advantage is that we don't drift, it will run at 15:00 exactly, every day...

     

    Anyway, at 15:00 we want to do stuff, in this case turning on and off sprinklers with a wait period. In a QA we can't really use fibaro.sleep as it blocks other interactions within the QA, so we usually use setTimeout.

     

    Here fibaroExtra has a convenient function 

    fibaro.sequence(....) 

    that runs commands with option delays using a setTimeout loop for us.

    The arguments are either a number being the delay (in ms) or a table {<function>,<arg1>,<arg2>,...} and the function will be called with the given arguments.

    Ex.

    fibaro.sequence({fibaro.call,88,'turnOn'},5*60*1000,{fibaro.call,88,'turnOff'})

    will call turnOff on device 88, wait for 5min and then call turnOff on the same device.

     

    In our example we want to turn on and off sprinklers.

    Please login or register to see this code.

     

    If we put it all together we get

    Please login or register to see this code.

     

    Compact, extensible, and easy to maintain code.

    Hey there,

    Unfortunatelly this doesnt work for me...Its just running all relays at the same moment..

    A created a debugged version, just to see, but its not waiting the time given

    Please login or register to see this code.

    ...

    Please login or register to see this attachment.

    Link to comment
    Share on other sites

  • Topic Author
  • Yes, but you specify the functions wrong. 

    Please login or register to see this code.

    actually makes the call directly. So all the debug statements run immediately that's why you see it all at the same time. The result of the debug call is nil so the fibaro.sequence has nothing to do...

     

    You need to write it like

    Please login or register to see this code.

    because self:debug is a method call you need to give self as the first argument again.

    So try

    Please login or register to see this code.

     

    Alternatively you could introduce your own log function

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

    2 minutes ago, jgab said:

    Yes, but you specify the functions wrong. 

    Please login or register to see this code.

    actually makes the call directly. So all the debug statements run immediately that's why you see it all at the same time. The result of the debug call is nil so the fibaro.sequence has nothing to do...

     

    You need to write it like

    Please login or register to see this code.

    because self:debug is a method call you need to give self as the first argument again.

    So try

    Please login or register to see this code.

     

    Alternatively you could introduce your own log function

    Please login or register to see this code.

     

    Many thanks, i will try.it.An if I have you on the phone :-), may I ask a last two quick question...Quesiotn 1.: I couldn't find a method, how to do a foerach loop where inside will be a settimeout function. or maybe your sequence funciton. Because its asynchronous style foreach runs down before settimout can take affect..I know why is this happening, but cant find a workaround,,,

     

    Example 

     

    Please login or register to see this code.

    And the 2nd question, then I wont bother you on friday...

    I saw you have there a function QuickApp:getView(elm,prop)  , which is incrediby usefull..I just can't find a way how to create UI elements on the fly. Example: In my QA there are separate buttons for each sprinkler, so if user wants, he can run them manualy..But if the user doesnt have 3 sprinklers, but only two, why would i put there 3 buttons, so i would like to create Buttons according to users sprinkler counts. Is it possible in Fibaro?

    Create UI element in LUA code?

    Thanks

     

    Link to comment
    Share on other sites

  • Topic Author
  • 54 minutes ago, Neo Andersson said:

    Many thanks, i will try.it.An if I have you on the phone :-), may I ask a last two quick question...Quesiotn 1.: I couldn't find a method, how to do a foerach loop where inside will be a settimeout function. or maybe your sequence funciton. Because its asynchronous style foreach runs down before settimout can take affect..I know why is this happening, but cant find a workaround,,,

    You need to create the argument list to sequence dynamically.

    Assume you have a list of the sprinkler and the time they should be on

    Please login or register to see this code.

     

    54 minutes ago, Neo Andersson said:

    And the 2nd question, then I wont bother you on friday...

    I saw you have there a function QuickApp:getView(elm,prop)  , which is incrediby usefull..I just can't find a way how to create UI elements on the fly. Example: In my QA there are separate buttons for each sprinkler, so if user wants, he can run them manualy..But if the user doesnt have 3 sprinklers, but only two, why would i put there 3 buttons, so i would like to create Buttons according to users sprinkler counts. Is it possible in Fibaro?

    Create UI element in LUA code?

    Dynamically creating UI elements are not for the fainthearted - there are some posts in the  QuickApp tips and tricks thread  in the forum.

    However, I would recommend you to have a fixed number of buttons 5+ and set the text of the buttons not needed to "" or "---"

    Link to comment
    Share on other sites

    17 hours ago, jgab said:

    The previous example used events and sequence to carry out the task.

    It turn out that post can also post a function (not only events). With the new fibaroExtra v0.920 we can make the example more... compact.

    Please login or register to see this code.

     

    Daer Jgab, how can we format the event post with a condition where posting would be depending on next day name. If user doesnt want scheduled irrigation on Wednesday, the event post in the loop shouldnt be happening if the next day is Wednesday.

     

    The other thing: Can we cancel an event which was already posted? I couldnt manage to find any description in your topic, how to cancel an event. You have there a function FIbaro.event(ref).cancel, but somewhere i saw that it cant be used for posted events, it only cancel the declaration so the event won't be posted next time, because it won't exist. Am i right?

     

    What happens with "RunIrrigation" event if its forexample posted once for 9:00, once for 11:00? The posting mechanism will overwrite the first one, or it will create a paralell instance and both events will be triggered? Thanks a lot for help

    Link to comment
    Share on other sites

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

     Share

    ×
    ×
    • Create New...