LUA Macros for BLI Manual

Lua Macros is a great tool to get the most out of your BeoLiving Intelligence and take your home automation installation to the next level.

The simplicity of programming in lua, a fast-to-learn and high level programming language, combined with specifically designed functions thought out especially for the BLI, give the installer/advanced-user freedom to get creative and design automation procedures that stand out.

The Macro configuration page of the BeoLiving Intelligence has a simple user interface that displays available resources and commands on these resources, but aside from selecting the command to execute and setting a time delay between commands, the possibilities are limited.

A user may desire to use their system variable’s values to act in different ways.

E.g.: Respond to the livingroom's light switch being pressed by turning the light on to full power during the day and 25% in the evening.

    function(event, engine)
      -- trigger event recieved from livingroom main light switch (BUTTON)
      time = engine.query("*/*/SYSTEM/Clock/")
      if tonumber(time[1].get_number("hour")) < 18 then -- this could also be done with sunrise/sunset relative times in the BLI
        engine.fire("Main/livingroom/DIMMER/main_light/SET?LEVEL=99")
      else
        engine.fire("Main/livingroom/DIMMER/main_light/SET?LEVEL=25")
      end
    end 
  

Much is possible with lua Macros. The following is an introduction to the main tools used in lua Macros programming for the BeoLiving Intelligence, including code snippets and practical examples.

How lua Macros work

When a macro is executed, either manually, by another Macro or because any of the defined events has matched, the function defined in the “Lua code” text area will be executed.

The function should have the following signature: function(event, engine)

Every lua Macro should start by stating the signature and end with end, e.g.:


  function(event, engine)
    -- all your code
  end

Parameters

The available parameters are those under event and under engine:

Event

The event that originated the call will have many parameters with information related to this event and this information can be useful for setting conditions or values of variables.

E.g. Get the level of a dimmer who’s change has triggered the event, and set half the value to all the other lights.

GET Functions

The get functions are some of the most important when programming lua Macros, as they are used to obtain the values of other parameters of an event. There are five different functions, according to the type (string, boolean, or number) you know the parameter should return.

If you use the incorrect function (eg: get_boolean for a parameter that will return a string) the BLI will attempt to interpret a coherent value (eg: if the string is "false" it will return the boolean false) and if it's not possible, it will send a warning and allow the Macro to continue excecution.

  • get_boolean (function(string): boolean): Gets the value of a parameter, excluding the updated mark. Returns data of the boolean type which can be used directly in conditionals (eg: if event.get_boolean("mute") then).
    event.get_boolean(“nowPlaying”) = true
  • get_number (function(string): number): Gets the value of a parameter, excluding the updated mark. Returns data of the number type which can be compared directely with numbers (eg: if event.get_number("volume") > 20 then).
    event.get_number(“LEVEL”) = 55
  • get_string (function(string): string): Gets the value of a parameter, excluding the updated mark. Returns data of the string type.
    event.get_string(“sourceName”) = “RADIO”
  • get_celsius (function(string): number): Gets the value of a parameter, excluding the updated mark. Returns the value of a temperature in celsius when available, in number type.
    event.get_celsius(“TEMPERATURE”) = 25
  • get_fahrenheit (function(string): number): Gets the value of a parameter, excluding the updated mark. Returns the value of a temperature in fahrenheit when available, in number type.
    event.get_fahrenheit(“TEMPERATURE”) = 77
Other Functions
  • tostring (function(): string): The full string representation of the event.
    event.tostring() = “Main/global/DIMMER/MyLamp/STATE_UPDATE?LEVEL=55!”
  • area (function(): string): The area name.
    event.area() = “Main”
  • zone (function(): string): The zone name.
    event.zone() = “global”
  • type (function(): string): The type name.
    event.type() = “DIMMER”
  • name (function(): string): The originator name.
    event.name() = “MyLamp”
  • parameters (function(): table): The parameters, with full values, as a lua table.
    event.parameters() = {“LEVEL” = “55!”}
  • updated (function(string): boolean): Checks whether a parameter was updated on the event.
    event.updated(“LEVEL”) = true
  • group (function(): string): The name of the group the zone is in.
    event.group() = “indoors”
  • group_zones (function(string) : table): The addresses of the zones contained in a group.
    event.group_zones(“indoors”) = {“Main/global”, “Downstairs/Kitchen”, “Upstairs/Main room”, “other/room”}
Engine

The BeoLiving Intelligence’s execution engine. The engine allows you te set values or query states of all your BLI’s devices.

Functions
  • fire (function(string, …)): Fires one or more commands on the engine.
    engine.fire(“other/room/DIMMER/*/SET?LEVEL = 75”)
  • fire_on_group (function(string, string)): Fires one commands every zone that belongs to a group.
    engine.fire_on_group(“indoors”, “DIMMER/*/SET?LEVEL = 75”)
  • query (function(string): table): Performs a state query on the engine. The returned table is an array of states, with the following members:
    • tostring (function(): string): The full string representation of the state.
    • area (function(): string): The area name.
    • zone (function(): string): The zone name.
    • type (function(): string): The type name.
    • name (function(): string): The state owner name.
    • get (function(string): string): Gets the value of a parameter.
    • group (function(): string): The name of the group the zone is in.
    • group_zones (function(string) : table): The addresses of the zones contained in a group.
      tab = engine.query(“other/room/DIMMER/*”)

      tab[1].get_boolean(“mute”) = false

      tab[1].get_number(“LEVEL”) = 62

      tab[1].get_string(“sourceName”) = “RADIO”

      tab[1].get_celsius(“TEMPERATURE”) = 25

      tab[1].get_fahrenheit(“TEMPERATURE”) = 77

      In this case the type is readily available, so if you use the incorrect get function, an error will be sent with information about the script and the macro will stop (eg: Error: Main/global/MACRO/dummy execution error: Line 2: Cannot convert VALUE to integer since it has type boolean).

      tab[1].tostring() = “other/room/DIMMER/OtherLamp/STATE_UPDATE?LEVEL=62”

      tab[1].area() = “other”

      tab[1].zone() = “room”

      tab[1].type() = “DIMMER”

      tab[1].name() = “OtherLamp”

      tab[1].group() = “indoors”

      tab[1].group_zones(“indoors”) = {“Main/global”, “Downstairs/Kitchen”, “Upstairs/Main room”, “other/room”}

  • wait_until (function(string, int, int): bool, string): Blocks the execution of the macro for a certain amount of time or until a given condition is met. Returns whether the condition was held and the address that matched.
    success, address = engine.wait_until(“other/room/AV renderer/TV/STATE_UPDATE?state=Play”, 120, 0)
  • delay (function(int, int)): Blocks the execution for a certain amount of time.
Return

No return value is expected or should be set from the lua function.

Guidance and useful information

Important functions

The tonumber() and tostring() functions are available to tranform values when programming lua Macros.

tostring(tonumber(event.get_string("_stringWithNumber"))==90) is equal to the string false if the _stringWithNumber parameter of the trigger event is not 90.

Common errors and Debugging

Common errors in lua Macros programming include the comparison of variables with different types of data (e.g. numbers and strings) and the specification of a Resource whose name has later been changed.

E.g.: The comparison event.get_boolean("mute") == "false" when checking in the event sent by a BeoLink product is muted is incorrect and will always return false. The correct comparison is event.get_boolean("mute") == false.

Any runtime error will be sent to the system log (Tools–>Log).

Example of what could be seen in log: Execution error on Main/global/MACRO/sample: Line 6: attempt to call field ‘wrong_delay’ (a nil value).

For debugging purposes, the macro code can call the Debug function, which receives a string that is sent to the system log. This can be used to print a variable’s value or to see if your macro is arriving to the end of the code or “crashing” before hand.

Example of what you can write in your Macro’s code: Debug(“Will debug: “ .. tostring(123)).

Extra commands

Two special commands, which cannot be added via normal macro edition, are available for group creation and group clear. These commands are provided by the system driver, which is located on the global zone.

Set the kitchen on the “indoors” group: Main/global/SYSTEM/BeoLiving Intelligence/SET GROUP?zone=Downstairs/Kitchen&group=indoors

Clear the kitchen group: Main/global/SYSTEM/BeoLiving Intelligence/CLEAR GROUP?zone=Downstairs/Kitchen

Only one execution of a macro is allowed to wait_until or delay at a time. If the macro is fired while the same macro is waiting or delaying, then the previous wait is canceled.

Canceling a macro immediately cancels any wait_until or delay.

Please take into account that lua Macros programming should prioritize using values from the parameters of the event and not from an independently queried resource.

Learn lua

All lua native functions are available for use in the lua Macros configuration.

A good place to start learning Lua is Tyler Neylon’s “Learn Lua in 15 Minutes”. This is a short and simple introduction

A more complete reference guide is the book Programming in Lua. The first edition is freely available online. And includes all available functiones.

Code examples

Feel free to browse our examples, many are short and ilustrate use cases very well.

Improve this document: Edit on github!