| LIRC libraries LinuxInfraredRemoteControl

lirctool.py
1 # Copyright (C) 2017 Bengt Martensson.
2
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or (at
6 # your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along with
14 # this program. If not, see http://www.gnu.org/licenses/.
15
16 """
17 This is a new and independent implementation of the Lirc irsend(1) program.
18 It offers a Python API and a command line interface. The command line
19 interface is almost, but not quite, compatible with irsend. Instead, it is
20 organized as a program with subcommands, send_once, etc.
21
22 There are some other subtile differences from irsend:
23
24 * subcommand must be lower case,
25 * send_once only takes one command (irsend takes several),
26 * send_stop without arguments uses the remote and the command from the last
27 send_start command,
28 * no need to give dummy empty arguments for list,
29 * The --count argument to send_once is argument to the subcommand.
30 * the code in list remote is suppressed, unless -c is given,
31 * port number must be given with the --port (-p) argument; hostip:portnumber
32 is not recognized,
33 * verbose option --verbose (-v)
34 * selectable timeout with --timeout (-t) option
35 * better error messages
36
37 It is using the new lirc Python API, including a C extension module.
38
39 For a GUI version, look at IrScrutinizer.
40 For a Java version, look at Javairtool
41 https://github.com/bengtmartensson/JavaLircClient
42 """
43
44 import argparse
45 import socket
46 import sys
47
48 import client
49
50 _DEFAULT_PORT = 8765
51
52
53 def _parse_commandline():
54 ''' Parse the command line, returns a filled-in parser. '''
55 # pylint: disable=bad-continuation
56 parser = argparse.ArgumentParser(
57 prog='irtool',
58 description="Tool to send IR codes and manipulate lircd(8)")
59 parser.add_argument(
60 "-a", "--address",
61 help='lircd host IP name or address, overrides --device.',
62 metavar="host", dest='address', default=None)
63 path = client.get_default_socket_path()
64 parser.add_argument(
65 '-d', '--device',
66 help='lircd socket path [%s]' % path, metavar="path",
67 dest='socket_pathname', default=None)
68 parser.add_argument(
69 '-p', '--port',
70 help='lircd IP port, use with --address [%d] ' % _DEFAULT_PORT,
71 dest='port', default=_DEFAULT_PORT, type=int)
72 parser.add_argument(
73 '-t', '--timeout',
74 help='Timeout in milliseconds [No timeout]', metavar="ms",
75 dest='timeout', type=int, default=None)
76 parser.add_argument(
77 '-V', '--version',
78 help='Display version information for irtool',
79 dest='versionRequested', action='store_true')
80 parser.add_argument(
81 '-v', '--verbose',
82 help='Have some commands executed verbosely',
83 dest='verbose', action='store_true')
84 subparsers = parser.add_subparsers(
85 dest='subcommand',
86 metavar='sub-commands')
87
88 # Command send_once
89 parser_send_once = subparsers.add_parser(
90 'send-once',
91 help='Send one command')
92 parser_send_once.add_argument(
93 '-#', '-c', '--count',
94 help='Number of times to send command in send_once',
95 dest='count', type=int, default=1)
96 parser_send_once.add_argument('remote', help='Name of remote')
97 parser_send_once.add_argument('command', help='Name of command')
98
99 # Command send_start
100 parser_send_start = subparsers.add_parser(
101 'send-start',
102 help='Start sending one command until stopped')
103 parser_send_start.add_argument(
104 'remote',
105 help='Name of remote')
106 parser_send_start.add_argument(
107 'command',
108 help='Name of command')
109
110 # Command send_stop
111 parser_send_stop = subparsers.add_parser(
112 'send-stop',
113 help='Stop sending the command from send_start')
114 parser_send_stop.add_argument(
115 'remote',
116 help='remote command')
117 parser_send_stop.add_argument(
118 'command',
119 help='remote command')
120
121 # Command list-remotes
122 subparsers.add_parser('list-remotes', help='List available remotes')
123
124 # Command list-keys
125 parser_list_keys = subparsers.add_parser(
126 'list-keys',
127 help='list defined keys in given remote')
128 parser_list_keys.add_argument(
129 'remote',
130 help='Name of remote')
131 parser_list_keys.add_argument(
132 "-c", "--codes",
133 help='List the numerical codes in lircd.conf, not just names',
134 dest='codes', action='store_true')
135
136 # Command driver-option
137 parser_drv_option = subparsers.add_parser(
138 'driver-option',
139 help='Set driver option to given value')
140 parser_drv_option.add_argument('option', help='Option name')
141 parser_drv_option.add_argument('value', help='Option value')
142
143 # Command set_input_logging
144 parser_set_input_log = \
145 subparsers.add_parser('set-inputlog', help='Set input logging')
146 parser_set_input_log.add_argument(
147 'log_file', nargs='?',
148 help='Path to log file, empty to inhibit logging', default='')
149
150 # Command set_driver_options
151 parser_set_driver_options = subparsers.add_parser(
152
153 'set-driver-options',
154 help='Set driver options')
155 parser_set_driver_options.add_argument('key', help='Option name')
156 parser_set_driver_options.add_argument('value', help='Option value')
157
158 # Command get version
159 subparsers.add_parser('version', help='Get lircd version')
160
161 # Command simulate
162 parser_simulate = subparsers.add_parser(
163 'simulate',
164 help='Fake the reception of IR signals')
165 parser_simulate.add_argument(
166 'remote',
167 help='remote part of simulated event')
168 parser_simulate.add_argument(
169 'key',
170 help='Name of command to be faked')
171 parser_simulate.add_argument(
172 'data',
173 help='Key press data to be sent to the Lircd')
174
175 # Command set_transmitters
176 parser_set_transmitters = subparsers.add_parser(
177 'set-transmitters',
178 help='Set transmitters')
179 parser_set_transmitters.add_argument(
180 'transmitters',
181 metavar='N', nargs='+', help="transmitter...")
182
183 args = parser.parse_args()
184
185 if args.versionRequested:
186 print("@version@")
187 sys.exit(0)
188 return args
189
190
191 def _send_once_command(connection, args):
192 ''' Perform a SEND_ONCE ... socket command. '''
193 if isinstance(args.keys, str):
194 args.keys = [args.keys]
195 command = client.SendCommand(connection, args.remote, args.keys)
196 parser = command.run(args.timeout)
197 if not parser.success:
198 print(parser.data[0])
199 return 0 if parser.success else 1
200
201
202 def _start_repeat_command(conn, args):
203 ''' Perform a SEND_START <remote> <key> socket command. '''
204 command = client.StartRepeatCommand(conn, args.remote, args.key)
205 parser = command.run(args.timeout)
206 if not parser.success:
207 print(parser.data[0])
208 return 0 if parser.success else 1
209
210
211 def _stop_repeat_command(conn, args):
212 ''' Perform a SEND_STOP <remote> <key> socket command. '''
213 command = client.StopRepeatCommand(conn, args.remote, args.key)
214 parser = command.run(args.timeout)
215 if not parser.success:
216 print(parser.data[0])
217 return 0 if parser.success else 1
218
219
220 def _drv_option_command(conn, args):
221 ''' Perform a "DRV_OPTION <option> <value>" socket command. '''
222 command = client.DrvOptionCommand(conn, args.option, args.value)
223 parser = command.run(args.timeout)
224 if not parser.success:
225 print(parser.data[0])
226 return 0 if parser.success else 1
227
228
229 def _list_keys_command(conn, args):
230 ''' Perform a irsend LIST <remote> socket command. '''
231 command = client.ListKeysCommand(conn, args.remote)
232 parser = command.run(args.timeout)
233 if not parser.success:
234 print(parser.data[0])
235 else:
236 if not args.codes and args.remote:
237 parser.data = [x.split()[-1] for x in parser.data]
238 for key in parser.data:
239 print(key)
240 return 0 if parser.success else 1
241
242
243 def _list_remotes_command(conn):
244 ''' Perform a irsend LIST command. '''
245 command = client.ListRemotesCommand(conn)
246 parser = command.run()
247 if not parser.success:
248 print(parser.data[0])
249 else:
250 for key in parser.data:
251 print(key)
252 return 0 if parser.success else 1
253
254
255 def _set_input_log_command(conn, args):
256 ''' Start or stop lircd logging using SET_LOGFILE socket command. '''
257 command = client.SetLogCommand(conn, args.logfile)
258 parser = command.run(args.timeout)
259 if not parser.success:
260 print(parser.data[0])
261 return 0 if parser.success else 1
262
263
264 def _simulate_command(conn, args, repeat=0):
265 ''' Roughly a irsend SIMULATE equivalent. '''
266 command = \
267 client.SimulateCommand(
268 conn, args.remote, args.key, repeat, args.data)
269 parser = command.run(args.timeout)
270 if not parser.success:
271 print(parser.data[0])
272 return 0 if parser.success else 1
273
274
275 def _transmitters_cmd(conn, args):
276 ''' Perform an irsend SET_TRANSMITTERS command. '''
277 command = client.SetTransmittersCommand(conn, args.transmitters)
278 parser = command.run(args.timeout)
279 if not parser.success:
280 print(parser.data[0])
281 return 0 if parser.success else 1
282
283
284 def _version_command(conn):
285 ''' Retrieve lircd version using the VERSION socket command. '''
286 command = client.VersionCommand(conn)
287 parser = command.run()
288 print(parser.data[0])
289 return 0 if parser.success else 1
290
291
292 def _not_implemented():
293 ''' Indeed, the not-implemented message '''
294 print("Subcommand not implemented yet, are YOU volunteering?")
295 return 2
296
297
298 def main():
299 ''' Indeed: main function. '''
300
301 args = _parse_commandline()
302 if args.address:
303 s = socket.socket((socket.AF_INET, socket.SOCK_STREAM))
304 s.connect((args.address, args.port))
305 conn = client.CommandConnection(s)
306 else:
307 conn = client.CommandConnection(args.socket_pathname)
308
309 cmd_table = {
310 'send-once':
311 lambda: _send_once_command(conn, args),
312 'send-start':
313 lambda: _start_repeat_command(conn, args),
314 'send-stop':
315 lambda: _stop_repeat_command(conn, args),
316 'list-keys':
317 lambda: _list_keys_command(conn, args),
318 'list-remotes':
319 lambda: _list_remotes_command(conn),
320 'set-inputlog':
321 lambda: _set_input_log_command(conn, args),
322 'simulate':
323 lambda: _simulate_command(conn, args),
324 'set-transmitters':
325 lambda: _transmitters_cmd(conn, args),
326 'driver-option':
327 lambda: _drv_option_command(conn, args),
328 'version':
329 lambda: _version_command(conn),
330 }
331 try:
332 if args.subcommand in cmd_table:
333 exitstatus = cmd_table[args.subcommand]()
334 else:
335 print('Unknown subcommand, use --help for syntax.')
336 exitstatus = 3
337
338 except ConnectionRefusedError:
339 print("Connection refused")
340 exitstatus = 5
341 except FileNotFoundError:
342 print("Could not find {0}".format(args.socket_pathname))
343 exitstatus = 5
344 except PermissionError:
345 print("No permission to open {0}".format(args.socket_pathname))
346 exitstatus = 5
347
348 sys.exit(exitstatus)
349
350
351 if __name__ == "__main__":
352 main()