Add LED control.
[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, sys
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 led_off():
121         os.system('echo 0 | sudo tee /sys/class/leds/led0/brightness')
122
123 def led_on():
124         os.system('echo 1 | sudo tee /sys/class/leds/led0/brightness')
125
126 def set_mode(newmode):
127         global mode
128         if mode != newmode:
129                 if newmode == VOMPILIRC_MODE_OFF:
130                         # we switch from either xbmc or vomp to off
131                         led_off()
132                 elif mode == VOMPILIRC_MODE_OFF:
133                         # we switch from off to either xbmc or vomp
134                         led_on()
135
136                 mode = newmode
137
138 def start_vomp():
139         global mode
140         global child_pipe
141         
142         if debug:
143                 print 'Starting vompclient'
144         
145         set_mode(VOMPILIRC_MODE_VOMP)
146         child_pipe = subprocess.Popen(['vompclient','-n'])
147
148 def start_xbmc():
149         global mode
150         global child_pipe
151         
152         if debug:
153                 print 'Starting XBMC'
154         
155         set_mode(VOMPILIRC_MODE_XBMC)
156         child_pipe = subprocess.Popen(['/usr/lib/xbmc/xbmc.bin', '--standalone'])
157
158
159 def tv_power(off=False):
160         pipe = subprocess.Popen(['cec-client', '-s'], stdin=subprocess.PIPE)
161         
162         if off:
163                 pipe.communicate('standby 0')
164         else:
165                 pipe.communicate('on 0')
166
167 def stop_child(force_off=False):
168         global mode
169         global child_pipe
170         
171         if debug:
172                 print 'Terminating child process'
173         
174         try:
175                 child_pipe.wait(5)
176         except:
177                 if debug:
178                         print 'Did not terminate within timeout, sending kill signal.'
179                         
180                 child_pipe.kill()
181                 child_pipe.wait()       
182         
183         if force_off:
184                 tv_power(off=True)
185                 
186         child_pipe = None
187         set_mode(VOMPILIRC_MODE_OFF)
188
189 def signal_handler(signum, frame):
190         if debug: print 'Exiting...'
191         
192         if child_pipe != None:
193                 stop_child()            
194                 
195         pylirc.exit()
196         os._exit(0)
197
198 def process_lirc_event():
199         global mode
200         global child_pipe
201         
202         s = pylirc.nextcode(1)
203                         
204         for code in s:
205                 vompmessage = ''
206                 if debug: print 'Command: %s, Repeat: %d' % (code['config'], code['repeat'])
207                 mapped_code = None
208                 try:
209                         mapped_code = '%i' % remote_map[code['config']]
210                 except:
211                         pass
212
213                 if mapped_code != None:
214                         vompmessage = mapped_code
215                 elif code['config'] == 'KEY_POWER':
216                         if code['repeat'] == 0:
217                                 if mode == VOMPILIRC_MODE_OFF:
218                                         start_vomp()
219                                 else:
220                                         stop_child(force_off=True)
221                 elif code['config'] == 'KEY_TV':
222                         if code['repeat'] == 0:
223                                 if mode == VOMPILIRC_MODE_OFF:
224                                         start_vomp()
225                                 elif mode == VOMPILIRC_MODE_XBMC:
226                                         stop_child(force_off=False)
227                                         start_vomp()
228                 elif code['config'] == 'KEY_VIDEO':
229                         if code['repeat'] == 0:
230                                 if mode == VOMPILIRC_MODE_OFF:
231                                         start_xbmc()
232                                 elif mode == VOMPILIRC_MODE_VOMP:
233                                         stop_child(force_off=False)
234                                         start_xbmc()
235                 else:
236                         sys.stderr.write('Unknown key: %s\n' % code['config'])
237
238                 if mode == VOMPILIRC_MODE_VOMP:
239                         if (len(vompmessage) > 0) and ((code['repeat'] == 0) or (vompmessage in repeaters)):
240                                 vomp_client.sendto(vompmessage, (vomp_host, vomp_port))
241                                         
242 if __name__ == '__main__':
243         try:
244                 vomp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
245         except socket.error, (value,message):
246                 sys.stderr.write('Failed to open UDP socket: "%s"\n' % message)
247                 sys.exit(1) 
248         
249         if pylirc.init('vompilirc', os.path.join('/etc/lirc/lircrc')):
250                 pylirc.blocking(1)
251
252                 signal.signal(signal.SIGINT, signal_handler)
253                 signal.signal(signal.SIGTERM, signal_handler)
254                 
255                 while True:
256                         process_lirc_event()
257         else:
258                 sys.stderr.write('Failed to init pylirc.\n')
259                 sys.exit(2)