Skip to content
Jean-Michaël Celerier edited this page Apr 26, 2017 · 5 revisions

Some devices in libossia can be specified through a high-level scripting language based on Javascript: QML. This allows to map protocols that are more low-level than protocols for which a tree structure is implicit such as OSC.

Learning QML

QML is first and foremost an UI language, hence most tutorials cover this aspect. The best reference available is the QML Book. Qt's QML reference can also be useful.

Using QML in libossia

Three protocols are currently based on QML :

  • HTTP
  • Serial
  • WebSockets

Planned future protocols are:

  • Raw TCP
  • Raw UDP
  • Raw ArtNet
  • HID

QML scripts have the general following structure:

import Ossia 1.0

QtObject
{
    function createTree() {
        return [ {
                    name: "tata",
                    children: [
                        {
                            name: "tutu",
                            type: Ossia.Float
                        }
                    ]
                 }
               ];
    }

    function onMessage(message) {
        [ { address: "/toto", value: 1234 } ];
    }

}

Two functions are to be provided by the user:

  • The main function, createTree, is called when initializing the devices. It should return a Javascript tree of objects: this tree will be used to create the device.

A node of the tree has the following API:

{
    name: "tata",
    type: Ossia.Float // Ossia.Int, Ossia.String, etc...
    value: 67.
    min: -12.
    max: 234
    access: Ossia.Get
    bounding: Ossia.Clip
    repetition_filter: true
    unit: "color.argb"
    description: "A good node"
    tags: ["intermedia", "post-humanism"]
    children: [ { name: ...} ]
   
    request: ...
    openListening: ...
    closeListening: ...
}

Not all fields have to be provided. Additionally, the protocols have special functions that can be provided in each node: request, openListening, closeListening.

Sending values

The request attribute can be either a function or a string. It corresponds to what will be sent through the protocol when a value is pushed.

String form:
request: "I send the value $val" 

If the pushed value is 3.56, the sent message will be

I send the value 3.56
Function form:
request: function(value) {
    return JSON.stringify({ ping: value })
}

If the pushed value is 3.56, the sent message will be

{ "ping": 3.56 }

Receiving messages

The onMessage function is called when a message is received through the protocol. It is up to the user to parse the message and take the relevant actions on the device.

The onMessage function takes as arguments a string, and returns an array of key-value pairs corresponding to addresses and values of the tree.

For instance, the following onMessage function will set the node /toto to 3.14 whenever a message is received:

function onMessage(value) 
{
    return [ { address: "/toto", value: 3.14 } ];
}

Websocket protocol

No specificities

Serial protocol

No specificities

HTTP protocol

The HTTP protocol is a request-response protocol. Hence, instead of a global onMessage function, each node provides a function that will be called when the answer is received.

For instance:

type: Ossia.Int
request: "https://jsonplaceholder.typicode.com/todos/$val" // try for instance with 3 or 4
answer: function(json) { // this website just returns some json
    return [ { address: "/toto", value: JSON.parse(json).title } ]
}