The lirc_client API


Since 0.6.0, the client API have supported receiving data. Since 0.9.2+, the API also supports sending of data. Since 0.10.0+ there is also a Python interface supporting both send and receive.

This text is also available in the API documentation (under Modules). This variant is more detailed, and linked by Doxygen to the sources.

Receiving data

If you only want to make your application to receive commands and if you don't want to mess with all the protocol stuff you can use the lirc_client library that comes with LIRC since version 0.6.0. With the help of this library a program can be as simple as this to receive data.


    /****************************************************************************
     ** irexec.c ****************************************************************
     ****************************************************************************
     *
     * irexec  - execute programs according to the pressed remote control buttons
     *
     * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
     * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
     *
     */

    #ifdef HAVE_CONFIG_H
    # include <config.h>
    #endif

    #include <errno.h>
    #include <unistd.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "lirc_client.h"

    char *progname;

    int main(int argc, char *argv[])
    {
            struct lirc_config *config;
            char *code;
            char *c;
            int ret;

            progname=argv[0];
            if(argc>2)
            {
                    fprintf(stderr,"Usage: %s <config file>\n",progname);
                    exit(EXIT_FAILURE);
            }
            if( lirc_init("irexec",1) == -1)
                    exit EXIT_FAILURE;

            if( lirc_readconfig(argc == 2 ? argv[1] : NULL,&config,NULL) == 0) {
                    while( lirc_nextcode(&code) == 0)
                    {
                            if (code == NULL) continue;
                            while(( ret = lirc_code2char( config,code,&c)) == 0 &&
                                  c != NULL)
                            {
                                   printf("Execing command \"%%s\"\\n",c);
                                   system(c);
                            }
                            free(code);
                            if(ret==-1) break;
                    }
                    lirc_freeconfig(config);
            }

            lirc_deinit();
            exit(EXIT_SUCCESS);
    }

Before anything else you have to include the header file for the lirc_client library. This is done with

    #include <lirc/lirc_client.h>

Note that our example differs in this point because it was taken directly from the lirc-0.6.0 source that comes with its own lirc_client.h but we have to use the one that is already installed on the system.

The next step is to initialize the library code with lirc_init(). This function connects to lircd and does some internal init stuff.

    int lirc_init(char *prog,int verbose);

The first argument to this function is the string users will have to provide as prog token in their .lircrc config files. If the second argument is non-zero error messages will be printed to stderr. Otherwise no error messages will ever be displayed. This function returns the file descriptor of the socket that is connected to lircd or -1 if an error occurred.

By default the client connects to the hard-coded default path, usually /var/run/lirc/lircd. The environment variable LIRC_SOCKET_PATH can be used to connect to another socket.

The example continues by reading a config file. This is done by the lirc_readconfig() function:

    int lirc_readconfig(char *file,struct lirc_config **config,
                        int (check)(char *s));

If you want to load the default config file you should pass NULL as first argument. If you want to load some other config file the file argument should contain the complete path to the file. Your program should give the user the possibility to use an other than the default config file. You should also be able to load multiple config files by calling this function several times.
The config argument is used to pass the pointer to the config file data structures back to your application. You will need it for calls to the lirc_code2char() function. The last argument is a call-back function that can be used to do syntax checks with the config strings. The library code will call the call-back function for all config strings where the prog token in the config file matches the prog string you provided with the lirc_init() function. If there is an error in the config string the call-back function should return -1, otherwise 0. If you don't need to do any syntax checks you can pass NULL here. The function returns -1 if an error occurred, 0 otherwise.

The lirc_nextcode() function blocks until there is something available on the lircd socket. This way it can be used in the main loop of your program like in our example.

    int lirc_nextcode(char **code);

If an error occurs (usually this means that the socket has been closed by the daemon) this function returns -1. Otherwise it returns 0 and code points to the next string available in the data stream. This string has to be freed by your application using the free(3) function. If no complete string is available code will be NULL.
If you use some GUI-toolkit for your program then you probably won't be able to use this function in your program's main loop because this is already handled by the GUI-toolkit. In this situation you should use the call-back abilities of the toolkit that will notify you whenever there is some input available from a file descriptor (you get the file descriptor from the lirc_init() function). E.g. you can use the gdk_input_add()/gdk_input_remove() functions with gtk or the QSocketNotifier class with Qt. If you don't have such functionality in your toolkit or can't use it for some reason you can still use SIGIO signals for this purpose. Check the documentation for your GUI-toolkit and signal(2) for further information.
Please note that using call-backs you still have to use some kind of while loop to read strings from the socket because several strings may be available in the data stream and you will only get a notification for the first one. This poses a problem for us because lirc_nextcode() blocks until there is something available from the socket which is not what we need here. You can solve this problem by setting the O_NONBLOCK flag for the socket using the fcntl(2) function. Have a look at the current xirw code that is available from the LIRC homepage for an implementation example.

To get the config string that the user has provided in the config file in response to a button press you use the following function:

    int lirc_code2char(struct lirc_config *config,char *code,char **string);

config is a pointer to the config file data structure that you can get with lirc_readconfig() and code is the code transmitted to your application on the lircd socket. If an action should be taken string will point to the config string the user has provided in the config file. The user might want to take several actions on a button press so you have to execute this function until string is NULL, which means that no more actions shall be taken, or an error occurs. The function returns -1 if an error occurred, 0 otherwise.

In our example there are only two clean-up functions to be explained.

    void lirc_freeconfig(struct lirc_config *config);

This functions frees the data structures associated with config.

    int lirc_deinit();

lirc_deinit() closes the connection to lircd and does some internal clean-up stuff.

Sending data

Sending (blasting) is done according to following:


#include "lirc_client.h"

int main(int argc, char** argv)
{
    int fd;

    fd = lirc_get_local_socket(NULL, 0);
    if (fd < 0) {
        // Process error
    }
    if (lirc_send_one(fd, "name of remote", "Key symbol") == -1) {
        // Process errors
    };
}

Notes:

lirc_send_one() and lirc_simulate() are blocking. If you need to do non-blocking IO and/or access other functionality available you need to use lirc_command_init() and lirc_command_run(). Example code is in irsend.cpp.

Using the Python API

The Python API's main documentation is in the API docs, look for Python Bindings under Modules. This text is just an introduction.

Besides the client API described here there are also lirc.config and lirc.database interfaces. These are not documented as of now. The config is some read-only paths as defined by configure. The database is the python view of the configs/ directory; example usage in lirc-setup and the data2table and data2html scripts in doc/

In the client API the receive parts supports both raw keypress events as displayed by irw(1) or application-specific strings as presented by ircat(1). Receiving raw events is done like:


    import lirc

    # Setup path, the lircd output socket path
    with lirc.RawConnection(path) as conn:
        press = conn.readline()
        # ... do something with press

The path argument can be omitted on default installations, lirc_client will make an educated guess based on environment, lirc_options.conf and hard-coded defaults.

Receiving application-specific strings goes like:

    import lirc

    # setup lircrc_path and program.
    with lirc.LircdConnection(
            program, lircrc_path, socket_path) as conn:
        while True:
             string = conn.readline()
             # ... do something with string

Here, user needs to define program (see ircat(1)), the path to the lircrc config file and the socket path. Like in previous example, lirc_client often can guess the socket_path and lircrc_path arguments in standard installations..

Sending is slightly more complex. A simple example is to retrieve the lircd version over the socket interface which is done like this:


    import lirc

    #... again, the path to the lircd socket might be needed
    with lirc.CommandConnection(socket_path=...) as conn:
        reply = lirc.VersionCommand(conn).run()
    if reply.success:
        print(parser.data[0])
    else:
        print("Error: " + parser.data[0])

The object returned by command.run() is a Reply with all info on the command outcome.

Asynchronous IO is relatively straight-forward. Using the AsyncConnection receiving data from a RawConnection or a LircdConnection goes like:


    import asyncio
    from lirc import AsyncConnection, LircdConnection

    async def get_lines(raw_conn):
        async with AsyncConnection(raw_conn, loop) as conn:
            async for keypress in conn:
                ... do something with keypress

    loop = asyncio.get_event_loop()
    with LircdConnection('foo',
                         socket_path=...,
                         lircrc_path=....) as conn:
        loop.run_until_complete(get_lines(conn))
    loop.close()


Besides the API docs there is also a directory doc/python-bindings in the distribution. This contains a bunch of small snippets which demonstrates the python API.

Autoconf support

LIRC has full support for autocont an pkg-config. To check for the lirc_client library all what is required is to insert the following into configure.ac:

    dnl Check for LIRC client support
    PKG_CHECK_MODULES([LIRC], [lirc],,)

This will setup the variables LIRC_FLAGS and LIRC_LIBS which can be used to augment AM_CPPFLAGS and AM_LIBS. See pkg-config(3).