Since 0.6.0, the client API have supported receiving data. Since 0.9.2+, the API also supports sending of data. Since 0.9.5+ 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.
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 (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.
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
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.
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:
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). 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()
Autoconf support
dnl Check for LIRC client support
PKG_CHECK_MODULES([LIRC], [lirc],,)