9e1a48d20ecf24071c2f3dc928a5aeb3ccf5c4c5
[vompilirc.git] / vompilirc.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """vompilirc.py: Routes remote commands received through LIRC to vompclient via UDP."""
5
6 #  Copyright (C) 2013  Alexander Koenig <alex@lisas.de>
7 #
8 #  This program is free software; you can redistribute it and/or modify
9 #  it under the terms of the GNU General Public License as published by
10 #  the Free Software Foundation; either version 2 of the License, or
11 #  (at your option) any later version.
12 #
13 #  This program is distributed in the hope that it will be useful,
14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #  GNU General Public License for more details.
17 #
18 #  You should have received a copy of the GNU General Public License
19 #  along with this program; if not, write to the Free Software
20 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21     
22 __author__ = "Alexander K├Ânig"
23 __email__ = "alex@lisas.de"
24 __license__ = "GPLv2"
25
26 import pylirc, time, socket, os, signal, subprocess
27
28 vomp_host = '127.0.0.1'
29 vomp_port = 2000
30 vomp_client = None
31
32 # VOMP remote commands as defined in remote.h
33
34 VOMP_NA_LEARN    = 101
35 VOMP_NA_NONE     = 98
36 VOMP_NA_UNKNOWN  = 99
37 VOMP_NA_SIGNAL   = 100
38 VOMP_DF_UP       = 94
39 VOMP_DF_DOWN     = 95
40 VOMP_DF_LEFT     = 96
41 VOMP_DF_RIGHT    = 97
42
43 VOMP_VOLUMEUP    = 16
44 VOMP_VOLUMEDOWN  = 17
45 VOMP_CHANNELUP   = 32
46 VOMP_CHANNELDOWN = 33
47
48 VOMP_ZERO        = 0
49 VOMP_ONE         = 1
50 VOMP_TWO         = 2
51 VOMP_THREE       = 3
52 VOMP_FOUR        = 4
53 VOMP_FIVE        = 5
54 VOMP_SIX         = 6
55 VOMP_SEVEN       = 7
56 VOMP_EIGHT       = 8
57 VOMP_NINE        = 9
58 VOMP_POWER       = 61
59 VOMP_GO          = 59
60 VOMP_BACK        = 31
61 VOMP_MENU        = 13
62 VOMP_RED         = 11
63 VOMP_GREEN       = 46
64 VOMP_YELLOW      = 56
65 VOMP_BLUE        = 41
66 VOMP_MUTE        = 15
67 VOMP_RADIO       = 12
68 VOMP_REVERSE     = 50
69 VOMP_PLAY        = 53
70 VOMP_FORWARD     = 52
71 VOMP_RECORD      = 55
72 VOMP_STOP        = 54
73 VOMP_PAUSE       = 48
74 VOMP_SKIPBACK    = 36
75 VOMP_SKIPFORWARD = 30
76 VOMP_OK          = 37
77
78 VOMP_FULL        = 60
79
80 VOMP_TV          = 28
81 VOMP_VIDEOS      = 24
82 VOMP_MUSIC       = 25
83 VOMP_PICTURES    = 26
84 VOMP_GUIDE       = 27
85 VOMP_UP          = 20
86 VOMP_DOWN        = 21
87 VOMP_LEFT        = 22
88 VOMP_RIGHT       = 23
89 VOMP_PREVCHANNEL = 18
90 VOMP_STAR        = 10
91 VOMP_HASH        = 14
92
93 VOMP_PLAYPAUSE   = 201
94
95 unhandled_map =  { 
96         'KEY_POWER': VOMP_POWER,'KEY_HOME': 0, 'KEY_TV': VOMP_TV, 'KEY_VIDEO': VOMP_VIDEOS, 'KEY_AUDIO': VOMP_MUSIC, 'KEY_CAMERA': VOMP_PICTURES
97         }
98
99 remote_map = { 
100         'KEY_EPG': VOMP_GUIDE,'KEY_RADIO': VOMP_RADIO,'KEY_UP': VOMP_UP,'KEY_DOWN': VOMP_DOWN,
101         'KEY_LEFT': VOMP_LEFT,'KEY_RIGHT': VOMP_RIGHT,'KEY_OK': VOMP_OK,'KEY_EXIT': VOMP_BACK,
102         'KEY_MENU': VOMP_MENU,'KEY_PREVIOUS': VOMP_PREVCHANNEL,'KEY_MUTE': VOMP_MUTE,
103         'KEY_VOLUMEUP': VOMP_VOLUMEUP,'KEY_VOLUMEDOWN': VOMP_VOLUMEDOWN,'KEY_CHANNELUP': VOMP_CHANNELUP,'KEY_CHANNELDOWN': VOMP_CHANNELDOWN,
104         'KEY_RECORD': VOMP_RECORD,'KEY_STOP': VOMP_STOP,'KEY_PLAY': VOMP_PLAY,'KEY_REWIND': VOMP_REVERSE,'KEY_FORWARD': VOMP_FORWARD,
105         'KEY_FRAMEBACK': VOMP_SKIPBACK,'KEY_PAUSE': VOMP_PAUSE,'KEY_FRAMEFORWARD': VOMP_SKIPFORWARD,
106         'KEY_1': VOMP_ONE,'KEY_2': VOMP_TWO,'KEY_3': VOMP_THREE,'KEY_4': VOMP_FOUR,'KEY_5': VOMP_FIVE,
107         'KEY_6': VOMP_SIX,'KEY_7': VOMP_SEVEN,'KEY_8': VOMP_EIGHT,'KEY_9': VOMP_NINE,
108         'KEY_KPASTERISK': VOMP_STAR,'KEY_0': VOMP_ZERO,'KEY_KPPLUS': VOMP_HASH,
109         'KEY_RED': VOMP_RED,'KEY_GREEN': VOMP_GREEN,'KEY_YELLOW': VOMP_YELLOW,'KEY_BLUE': VOMP_BLUE
110 }
111
112 (VOMPILIRC_MODE_OFF, VOMPILIRC_MODE_VOMP, VOMPILIRC_MODE_XBMC) = (0, 1, 2)
113
114 mode = VOMPILIRC_MODE_OFF
115 child_pipe = None
116
117 repeaters = [ VOMP_CHANNELUP, VOMP_CHANNELDOWN ]
118 debug = False
119
120 def start_vomp():
121         global mode
122         global child_pipe
123         
124         if debug:
125                 print 'Starting vompclient'
126         
127         mode = VOMPILIRC_MODE_VOMP
128         child_pipe = subprocess.Popen(['vompclient','-n'])
129
130 def start_xbmc():
131         global mode
132         global child_pipe
133         
134         if debug:
135                 print 'Starting XBMC'
136         
137         mode = VOMPILIRC_MODE_XBMC
138         child_pipe = subprocess.Popen(['/usr/lib/xbmc/xbmc.bin', '--standalone'])
139
140
141 def tv_power(off=False):
142         pipe = subprocess.Popen(['cec-client', '-s'], stdin=subprocess.PIPE)
143         
144         if off:
145                 pipe.communicate('standby 0')
146         else:
147                 pipe.communicate('on 0')
148
149 def stop_child(force_off=False):
150         global mode
151         global child_pipe
152         
153         if debug:
154                 print 'Terminating child process'
155         
156         try:
157                 child_pipe.wait(5)
158         except:
159                 if debug:
160                         print 'Did not terminate within timeout, sending kill signal.'
161                         
162                 child_pipe.kill()
163                 child_pipe.wait()       
164         
165         if force_off:
166                 tv_power(off=True)
167                 
168         child_pipe = None
169         mode = VOMPILIRC_MODE_OFF
170
171 def signal_handler(signum, frame):
172         if debug: print 'Exiting...'
173         
174         if child_pipe != None:
175                 stop_child()            
176                 
177         pylirc.exit()
178         os._exit(0)
179
180 def process_lirc_event():
181         global mode
182         global child_pipe
183         
184         s = pylirc.nextcode(1)
185                         
186         for code in s:
187                 vompmessage = ''
188                 if debug: print 'Command: %s, Repeat: %d' % (code['config'], code['repeat'])
189                 mapped_code = None
190                 try:
191                         mapped_code = '%i' % remote_map[code['config']]
192                 except:
193                         pass
194
195                 if mapped_code != None:
196                         vompmessage = mapped_code
197                 elif code['config'] == 'KEY_POWER':
198                         if code['repeat'] == 0:
199                                 if mode == VOMPILIRC_MODE_OFF:
200                                         start_vomp()
201                                 else:
202                                         stop_child(force_off=True)
203                 elif code['config'] == 'KEY_TV':
204                         if code['repeat'] == 0:
205                                 if mode == VOMPILIRC_MODE_OFF:
206                                         start_vomp()
207                                 elif mode == VOMPILIRC_MODE_XBMC:
208                                         stop_child(force_off=False)
209                                         start_vomp()
210                 elif code['config'] == 'KEY_VIDEO':
211                         if code['repeat'] == 0:
212                                 if mode == VOMPILIRC_MODE_OFF:
213                                         start_xbmc()
214                                 elif mode == VOMPILIRC_MODE_VOMP:
215                                         stop_child(force_off=False)
216                                         start_xbmc()
217                 else:
218                         sys.stderr.write('Unknown key: %s\n' % code['config'])
219
220                 if mode == VOMPILIRC_MODE_VOMP:
221                         if (len(vompmessage) > 0) and ((code['repeat'] == 0) or (vompmessage in repeaters)):
222                                 vomp_client.sendto(vompmessage, (vomp_host, vomp_port))
223                                         
224 if __name__ == '__main__':
225         try:
226                 vomp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
227         except socket.error, (value,message):
228                 sys.stderr.write('Failed to open UDP socket: "%s"\n' % message)
229                 sys.exit(1) 
230         
231         if pylirc.init('vompilirc', os.path.join('/etc/lirc/lircrc')):
232                 pylirc.blocking(1)
233
234                 signal.signal(signal.SIGINT, signal_handler)
235                 signal.signal(signal.SIGTERM, signal_handler)
236                 
237                 while True:
238                         process_lirc_event()
239         else:
240                 sys.stderr.write('Failed to init pylirc.\n')
241                 sys.exit(2)