oopsie dumb file
[teletype.git] / python / twitter / teletype-twitter.py
1 import time
2 import binascii
3 import urllib # for url unquote
4 import threading
5 import pigpio
6 import tweepy
7 import json
8 import requests
9 import logging
10 import time
11 import credentials
12
13 pi = pigpio.pi() # connect to local Pi
14
15 consumer_key = credentials.API_key
16 consumer_secret_key = credentials.API_secret_key
17 access_token = credentials.access_token
18 access_token_secret = credentials.access_token_secret
19
20 auth = tweepy.OAuthHandler(consumer_key, consumer_secret_key)
21 auth.set_access_token(access_token, access_token_secret)
22 api = tweepy.API(auth)
23
24 try:
25     api.verify_credentials()
26     print("Authentication Successful")
27 except:
28     print("Authentication Error")
29
30 pi.set_mode(2, pigpio.OUTPUT)
31
32 gpio8period      = 20 # period of 1 bit to achieve 45bps was 20
33
34 ColumnCurrentPosition = 1
35 ColumnMax             = 68
36
37 # first we map ascii to the possible ascii chars
38 ascii_to_baudot_char = {
39   'a':'A',
40   'b':'B',
41   'c':'C',
42   'd':'D',
43   'e':'E',
44   'f':'F',
45   'g':'G',
46   'h':'H',
47   'i':'I',
48   'j':'J',
49   'k':'K',
50   'l':'L',
51   'm':'M',
52   'n':'N',
53   'o':'O',
54   'p':'P',
55   'q':'Q',
56   'r':'R',
57   's':'S',
58   't':'T',
59   'u':'U',
60   'v':'V',
61   'w':'W',
62   'x':'X',
63   'y':'Y',
64   'z':'Z',
65   'A':'A',
66   'B':'B',
67   'C':'C',
68   'D':'D',
69   'E':'E',
70   'F':'F',
71   'G':'G',
72   'H':'H',
73   'I':'I',
74   'J':'J',
75   'K':'K',
76   'L':'L',
77   'M':'M',
78   'N':'N',
79   'O':'O',
80   'P':'P',
81   'Q':'Q',
82   'R':'R',
83   'S':'S',
84   'T':'T',
85   'U':'U',
86   'V':'V',
87   'W':'W',
88   'X':'X',
89   'Y':'Y',
90   'Z':'Z',
91   '1':'1',
92   '2':'2',
93   '3':'3',
94   '4':'4',
95   '5':'5',
96   '6':'6',
97   '7':'7',
98   '8':'8',
99   '9':'9',
100   '0':'0',
101   '-': '-',
102   '?': '?',
103   ':': ':',
104   '$': '$',
105   '!': '!',
106   '&': '&',
107   '#': '#',
108   '(': '(',
109   ')': '(',
110   '.': '.',
111   ',': ',',
112   '\'': '\'',
113   '/': '/',
114   '"': '"',
115   ' ': ' ' 
116 }
117
118 # then we map limted set to baudot
119 # see http://rabbit.eng.miami.edu/info/baudot.html
120 ascii_to_binstr = {
121   'A'  : '00011',
122   'B'  : '11001',
123   'C'  : '01110',
124   'D'  : '01001',
125   'E'  : '00001',
126   'F'  : '01101',
127   'G'  : '11010',
128   'H'  : '10100',
129   'I'  : '00110',
130   'J'  : '01011',
131   'K'  : '01111',
132   'L'  : '10010',
133   'M'  : '11100',
134   'N'  : '01100',
135   'O'  : '11000',
136   'P'  : '10110',
137   'Q'  : '10111',
138   'R'  : '01010',
139   'S'  : '00101',
140   'T'  : '10000',
141   'U'  : '00111',
142   'V'  : '11110',
143   'W'  : '10011',
144   'X'  : '11101',
145   'Y'  : '10101',
146   'Z'  : '10001',
147   '1'  : '10111',
148   '2'  : '10011',
149   '3'  : '00001',
150   '4'  : '01011',
151   '5'  : '10000',
152   '6'  : '10101',
153   '7'  : '00111',
154   '8'  : '00110',
155   '9'  : '11000',
156   '0'  : '10110',
157   '-'  : '00011',
158   '?'  : '11001',
159   ':'  : '01110',
160   '$'  : '01001',
161   '!'  : '01101',
162   '&'  : '11010',
163   '#'  : '10100',
164   '('  : '01111',
165   ')'  : '10010',
166   '.'  : '11100',
167   ','  : '01100',
168   '\'' : '01010',
169   '/'  : '11101',
170   '"'  : '11101',
171   ' '  : '00100'
172 }
173
174 needs_shift_up = (
175   '1',
176   '2',
177   '3',
178   '4',
179   '5',
180   '6',
181   '7',
182   '8',
183   '9',
184   '0',
185   '-',
186   '?',
187   ':',
188   '$',
189   '!',
190   '&',
191   '#',
192   '(',
193   ')',
194   '.',
195   ',',
196   '\'',
197   '/',
198   '"'
199 )
200
201 #def init(gpio_arg):
202 def init():
203   """
204   initialize teletype i/o
205   """
206   txbaudot("01000") # cr
207   time.sleep(1.0)
208   txbaudot("00010") # lf
209
210
211 def finish():
212   txbaudot("11111")
213   init()
214
215 # establish timer for TTY Motor
216
217 def motor_start(time_secs=0):
218   """
219   turn on motor
220   """
221   global MotorTimerCtr, MotorTimerVal
222
223   if (not MotorTimerCtr) :
224     #print "Motor start"
225     gpio.output(PWR_RLY,gpio.LOW)
226     time.sleep(.25)
227   
228   if not time_secs:
229     MotorTimerCtr = MotorTimerVal
230   else:
231     #print "motor_start(): non-standard timeout value: %d" % time_secs
232     MotorTimerCtr = time_secs
233
234 def motor_stop():
235   """
236   turn off motor, turn off data relay
237   """
238   global MotorTimerCtr
239   gpio.output(PWR_RLY,gpio.HIGH)
240   time.sleep(2.0)
241   gpio.output(DATA_RLY,gpio.HIGH)
242   MotorTimerCtr = 0
243
244 def test(s):
245   """
246   various tests
247   """
248   if (s == 'allpats'):
249     """
250     test mapping tables by attempt to print out all possible codes
251     """
252     #print 'allpats'
253     for i in range(0,256):
254       if (ascii_to_baudot_char.has_key(chr(i))): # if first reduce mapping table has key
255         a = ascii_to_baudot_char[chr(i)]
256         #print 'ascii_to_baudot_char(%d): %s' % (i,a)
257         if (ascii_to_binstr.has_key(a)): # and 2nd reduce mapping table has key
258           b = ascii_to_binstr[a]
259           if (b != '00000'):
260             #print 'test(%s)' % (a)
261             txbaudot(b)
262    
263 def txbaudot(c):
264   """
265   transmit one character to the teletype
266   """
267
268   #here
269   global pi
270   gpio=2
271   #print(c)
272   #motor_start()
273
274   pi.wave_clear()
275   wf=[]
276   micros = gpio8period*1000
277
278   wf.append(pigpio.pulse(0, 1<<gpio, 20000))
279
280   for b in reversed(c):
281     if (int(b) == 1):
282       wf.append(pigpio.pulse(1<<gpio, 0, micros))
283     else:
284       wf.append(pigpio.pulse(0, 1<<gpio, micros))
285
286   wf.append(pigpio.pulse(1<<gpio, 0, micros))
287   pi.wave_add_generic(wf)
288
289   wid = pi.wave_create()
290
291   if wid >= 0:
292     pi.wave_send_once(wid)
293
294   while pi.wave_tx_busy():
295     time.sleep(0.2)
296
297   #timer was .1 / .07
298   time.sleep(.05)
299
300 def txbin(s):
301   txbaudot(s)
302
303 def tx_keycode(s):
304   #print 'tx_keycode(%s)' % (s)
305   k = int(s)
306   if (ascii_to_baudot_char.has_key(chr(k))):
307       a = ascii_to_baudot_char[chr(k)]
308       #print 'ascii_to_baudot_char(%d): %s' % (i,a)
309       if (ascii_to_binstr.has_key(a)): # and 2nd reduce mapping table has key
310         b = ascii_to_binstr[a]
311         #print 'tx_keycode() %d (%s) -> (%s)' % (k,chr(k),b)
312         if (b != '00000'):
313           #print 'tx_keycode(%s)' % (b)
314           txbaudot(b)
315
316 shifted = False
317
318 def update_column_position():
319   """
320   keep track of column position so we can insert cr lf when necessary
321   """
322   global ColumnCurrentPosition, ColumnMax
323   ColumnCurrentPosition = ColumnCurrentPosition + 1
324   if ColumnCurrentPosition > ColumnMax:
325     #print "update_column_position(): col 0"
326     tx_ctl('cr')
327     tx_ctl('lf')
328     ColumnCurrentPosition = 0; 
329     #print "column reset to 0"
330
331 def shift_up():
332   """
333   Shift up to figures
334   """
335   global shifted
336   if not shifted:
337     tx_ctl('figs')
338     shifted = True
339
340 def shift_down():
341   """
342   Shift down to letters
343   """
344   global shifted
345   if shifted:
346     tx_ctl('ltrs')
347     shifted = False
348
349
350 def tx_ascii_chr(c):
351   """
352   send an ascii character
353   """
354   if (ascii_to_baudot_char.has_key(c)):
355       a = ascii_to_baudot_char[c]
356       #print 'ascii_to_baudot_char(%d): %s' % (i,a)
357       if (ascii_to_binstr.has_key(a)): # and 2nd reduce mapping table has key
358         b = ascii_to_binstr[a]
359         if (b != '00000'):
360           #print 'tx_ascii_chr(%s)' % (b)
361           if (a in needs_shift_up):
362             shift_up()
363           else:
364             shift_down()
365           txbaudot(b)
366           update_column_position()
367
368
369
370 def tx(c):
371   """
372   send an ascii character
373   """
374   tx_keycode(c)
375
376 def tx_str(s):
377   """
378   transmit an ascii string
379   """
380   de_uried_str = urllib.unquote(s)
381   for i in range(len(de_uried_str)):
382     #print '[%s]' % de_uried_str[i]
383     tx_ascii_chr(de_uried_str[i])
384
385
386 def tx_ctl(c):
387   """
388   transmit a control code 'lf' = line feed, 'cr' = carriage return, etc.
389   """
390   global ColumnCurrentPosition
391   #print "tx_ctl(%s)" % c
392   if (c == 'cr'):
393     txbaudot('01000')
394     ColumnCurrentPosition = 0
395   elif (c == 'lf'):
396     txbaudot('00010')
397   elif (c == 'figs'):
398     txbaudot('11011')
399   elif (c == 'ltrs'):
400     txbaudot('11111')
401   elif (c == 'bell'):
402     txbaudot('11011') # shift up
403     txbaudot('00101')
404     txbaudot('11111') # shift down
405     txbaudot('01000') # cr
406     txbaudot('00100') # space
407     txbaudot('00100')
408     txbaudot('00100')
409     txbaudot('00100')
410     txbaudot('00100')
411     txbaudot('00100')
412     txbaudot('00100')
413     txbaudot('00100')
414     txbaudot('01000') # cr
415     ColumnCurrentPosition = 0
416   elif (c == 'null'):
417     txbaudot('00000')
418   elif (c == 'space'):
419     txbaudot('00100')
420     update_column_position()
421
422 init()
423
424 FILE_NAME = 'last_seen_id.txt'
425
426 def retrieve_last_seen_id(file_name):
427     f_read = open(file_name, 'r')
428     last_seen_id = int(f_read.read().strip())
429     f_read.close()
430     return last_seen_id
431
432 def store_last_seen_id(last_seen_id, file_name):
433     f_write = open(file_name, 'w')
434     f_write.write(str(last_seen_id))
435     f_write.close()
436     return
437
438 def reply_to_tweets():
439     #print('retrieving and replying to tweets...', flush=True)
440     # DEV NOTE: use 1060651988453654528 for testing.
441     last_seen_id = retrieve_last_seen_id(FILE_NAME)
442     # NOTE: We need to use tweet_mode='extended' below to show
443     # all full tweets (with full_text). Without it, long tweets
444     # would be cut off.
445     mentions = api.mentions_timeline(
446                         last_seen_id,
447                         tweet_mode='extended')
448     for mention in reversed(mentions):
449         #print(str(mention.id) + ' - ' + mention.full_text, flush=True)
450         init()
451         tx_str(mention.full_text)
452         init()
453         last_seen_id = mention.id
454         store_last_seen_id(last_seen_id, FILE_NAME)
455         if '#tweetateletype' in mention.full_text.lower():
456             #print('found the magic word!', flush=True)
457             #print('responding back...', flush=True)
458             api.update_status('@' + mention.user.screen_name +
459                     '#Howdy do back to you!', mention.id)
460
461 while True:
462     reply_to_tweets()
463     time.sleep(15)