Advertisement
Guest User

Untitled

a guest
Jun 26th, 2018
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.61 KB | None | 0 0
  1. import signal
  2. from configparser import ConfigParser
  3. import threading
  4. import queue
  5. import datetime
  6. import serial
  7. import pymysql
  8. import csv
  9. import time
  10. from tkinter import *
  11. from tkinter.font import Font
  12. import sys
  13. from DBUtils.PersistentDB import PersistentDB
  14. from messaging.sms import SmsSubmit, SmsDeliver
  15.  
  16.  
  17. class deviceThread(threading.Thread):
  18.     def __init__(self, queue, usb_id):
  19.         threading.Thread.__init__(self)
  20.         self.queue = queue
  21.  
  22.         self.usb_id = usb_id
  23.  
  24.         self.sms_pdu_mode = None
  25.  
  26.         self.service_mode = False
  27.  
  28.         self.device = serial.Serial('/dev/ttyUSB' + str(self.usb_id), 115200, timeout=0)
  29.         devices.append(self.device)
  30.  
  31.         self.sim = {
  32.             'id': '',
  33.             'iccid': '',
  34.             'phone': ''
  35.         }
  36.  
  37.         self.sms_queue = []
  38.  
  39.     def run(self):
  40.         self.log('USB-' + str(self.usb_id))
  41.  
  42.         self.network_registration()
  43.  
  44.         if self.sim['iccid'] == cfg.get('service-sim', 'iccid'):
  45.             self.service_mode = True
  46.  
  47.         self.device_registration()
  48.  
  49.         if self.service_mode is True:
  50.             self.log('SERVICE MODE')
  51.             self.wait_for_service_request()
  52.         else:
  53.             self.log('BOT MODE')
  54.             self.handle_registration_code()
  55.  
  56.     def network_registration(self):
  57.         self.log('Set GSM mode')
  58.         self.device.write('AT+CSCS="GSM"\r'.encode())
  59.         if self.read_ok_error() is False:
  60.             sys.exit(2)
  61.  
  62.         self.log('Set SMS storage')
  63.         self.device.write('AT+CPMS="SM"\r'.encode())
  64.         if self.read_ok_error() is False:
  65.             sys.exit(2)
  66.  
  67.         self.log('Clean-up SMS storage')
  68.         self.device.write('AT+CMGD=1,4\r'.encode())
  69.         if self.read_ok_error() is False:
  70.             sys.exit(2)
  71.  
  72.         self.device.write('AT+CCID\r'.encode())  # check SIM ID
  73.         self.wait_for_message('AT+CCID')
  74.         self.sim['iccid'] = self.read_data()
  75.         self.read_ok_error()
  76.  
  77.         self.log('ICCID: ' + self.sim['iccid'])
  78.  
  79.         mii = self.sim['iccid'][0:2]
  80.         if mii != '89':
  81.             self.log('SIM ERROR!')
  82.             sys.exit(2)
  83.  
  84.         cc = self.sim['iccid'][2:5]
  85.         if cc != '852':
  86.             self.log('Non HK SIM!')
  87.             sys.exit(2)
  88.  
  89.         mnc = self.sim['iccid'][5:7]
  90.         register_mnc = ''
  91.  
  92.         if mnc == '00':
  93.             operator = 'HKT GSM900'
  94.         elif mnc == '01':
  95.             operator = 'CITIC MVNO'
  96.         elif mnc == '02':
  97.             operator = 'HKT 3G'
  98.             register_mnc = '00'
  99.         elif mnc == '03':
  100.             operator = 'Hutchison 3G'
  101.             register_mnc = '04'
  102.         elif mnc == '04':
  103.             operator = 'Hutchison GSM900/1800'
  104.         elif mnc == '05':
  105.             operator = 'Hutchison CDMA'
  106.             register_mnc = '04'
  107.         elif mnc == '06':
  108.             operator = 'SmarTone GSM900'
  109.         elif mnc == '07':
  110.             operator = 'China Unicom MVNO'
  111.         elif mnc == '08':
  112.             operator = 'Truphone MVNO'
  113.         elif mnc == '09':
  114.             operator = 'CMMobile MVNO'
  115.         elif mnc == '10':
  116.             operator = 'HKT GSM1800'
  117.         elif mnc == '11':
  118.             operator = 'China-Hongkong Telecom MVNO'
  119.         elif mnc == '12':
  120.             operator = 'China Mobile GSM1800'
  121.         elif mnc == '13':
  122.             operator = 'China Mobile MVNO'
  123.         elif mnc == '14':
  124.             operator = 'Hutchison GSM1800'
  125.         elif mnc == '15':
  126.             operator = 'SmarTone 3G'
  127.             register_mnc = '06'
  128.         elif mnc == '16':
  129.             operator = 'HKT GSM1800'
  130.         elif mnc == '17':
  131.             operator = 'SmarTone GSM1800'
  132.         elif mnc == '18':
  133.             operator = 'HKT GSM1800'
  134.         elif mnc == '19':
  135.             operator = 'HKT 3G'
  136.         elif mnc == '20':
  137.             operator = 'HKT LTE'
  138.             register_mnc = '00'
  139.         elif mnc == '21':
  140.             operator = '21Vianet MVNO'
  141.         elif mnc == '22':
  142.             operator = '263 Mobile'
  143.         elif mnc == '23':
  144.             operator = 'Lycamobile'
  145.         elif mnc == '24':
  146.             operator = 'Multibyte Info Technology'
  147.         elif mnc == '29':
  148.             operator = 'HKT CDMA2000'
  149.             register_mnc = '00'
  150.         elif mnc == '31':
  151.             operator = 'China Telecom MVNO'
  152.         elif mnc == '32':
  153.             operator = 'HKBN MVNO'
  154.         elif mnc == '33':
  155.             operator = 'Tai Tung Mobile MVNO'
  156.         else:
  157.             operator = ''
  158.  
  159.         if operator != '':
  160.             self.log(operator)
  161.         else:
  162.             self.log('Operator not supported')
  163.             sys.exit(1)
  164.  
  165.         if register_mnc == '':
  166.             self.device.write('AT+COPS=0\r'.encode())
  167.         else:
  168.             self.log('Manual register to network 454' + register_mnc)
  169.             c = 'AT+COPS=1,2,"454' + register_mnc + '"'
  170.             self.device.write((c + '\r').encode())
  171.             self.wait_for_message(c)
  172.  
  173.         if self.read_ok_error() is True:
  174.             self.log('Registered on the network')
  175.  
  176.             conn = persist.connection()
  177.             cursor = conn.cursor()
  178.             cursor.execute(
  179.                 "SELECT `id`, `phone` FROM `sim` WHERE `iccid` = '%s'" %
  180.                 self.sim['iccid']
  181.             )
  182.             data = cursor.fetchone()
  183.  
  184.             if data is None:
  185.                 self.log('Making a call to activate SIM card')
  186.                 self.device.write('ATD1878200;\r'.encode())
  187.                 time.sleep(60)
  188.                 self.device.write('AT+CHUP\r'.encode())
  189.  
  190.                 self.send_sms(SERVICE_PHONE, 'WHO AM I?', pdu=False)
  191.                 sms = self.wait_for_sms(SERVICE_PHONE, pdu=False)
  192.                 self.sim['phone'] = sms['content']
  193.  
  194.                 self.log('Phone number is ' + self.sim['phone'])
  195.                 cursor.execute(
  196.                     "INSERT INTO `sim` (`iccid`, `phone`) VALUES ('%s', '%s')" %
  197.                     (
  198.                         self.sim['iccid'],
  199.                         self.sim['phone']
  200.                     )
  201.                 )
  202.                 conn.commit()
  203.                 self.sim['id'] = cursor.lastrowid
  204.             else:
  205.                 self.sim['id'] = data[0]
  206.                 self.sim['phone'] = data[1]
  207.                 self.log("Number from DB: " + self.sim['phone'])
  208.  
  209.             cursor.close()
  210.             conn.close()
  211.  
  212.             return
  213.         else:
  214.             self.log('Failed to register')
  215.             sys.exit(2)
  216.  
  217.     def set_sms_mode(self, pdu=False):
  218.         if pdu is False and self.sms_pdu_mode is not False:
  219.             self.log('Set text mode')
  220.             self.device.write('AT+CMGF=1\r'.encode())
  221.         elif pdu is True and self.sms_pdu_mode is not True:
  222.             self.log('Set PDU mode')
  223.             self.device.write('AT+CMGF=0\r'.encode())
  224.         else:
  225.             return
  226.  
  227.         self.read_ok_error()
  228.         self.sms_pdu_mode = pdu
  229.         return
  230.  
  231.     def device_registration(self):
  232.         conn = persist.connection()
  233.         cursor = conn.cursor()
  234.         cursor.execute("SELECT `id` FROM `device` WHERE `usb_id` = '%s'" % self.usb_id)
  235.         data = cursor.fetchone()
  236.  
  237.         if self.service_mode is True:
  238.             status = 'server'
  239.         else:
  240.             status = 'idle'
  241.  
  242.         if data is None:
  243.             self.log('Recording device')
  244.  
  245.             cursor.execute(
  246.                 "INSERT INTO `device` (`usb_id`, `sim_id`, `status`) VALUES ('%s', '%s', '%s')" %
  247.                 (
  248.                     self.usb_id,
  249.                     self.sim['id'],
  250.                     status
  251.                 )
  252.             )
  253.  
  254.             self.device_id = int(cursor.lastrowid)
  255.         else:
  256.             self.log('Updating device')
  257.  
  258.             self.device_id = int(data[0])
  259.             cursor.execute(
  260.                 "UPDATE `device` SET `sim_id` = '%s', `status` = '%s' WHERE `usb_id` = '%s' LIMIT 1" %
  261.                 (
  262.                     self.sim['id'],
  263.                     status,
  264.                     self.usb_id
  265.                 )
  266.             )
  267.  
  268.         conn.commit()
  269.         cursor.close()
  270.         conn.close()
  271.  
  272.     def read_data(self, return_if_cmd=False):
  273.         buffer = ''
  274.  
  275.         while True:
  276.             data = self.device.read().decode()
  277.             if data != '':
  278.                 if data == '>':
  279.                     return '>'
  280.                 elif data != "\r" and data != "\n":
  281.                     buffer = buffer + data
  282.                 elif buffer != '':
  283.                     if buffer[0: 11] == '+CMTI: "SM"':
  284.                         k = buffer[12:]
  285.                         self.sms_queue.append(k)
  286.  
  287.                         if return_if_cmd is True:
  288.                             return
  289.                         else:
  290.                             buffer = ''
  291.                     else:
  292.                         return buffer
  293.             else:
  294.                 self.check_signal()
  295.                 time.sleep(0.25)
  296.  
  297.     def read_ok_error(self):
  298.         m = self.read_data()
  299.  
  300.         while m != 'OK' and m != 'ERROR':
  301.             m = self.read_data()
  302.  
  303.         if m == 'OK':
  304.             return True
  305.         else:
  306.             return False
  307.  
  308.     def wait_for_message(self, w):
  309.         m = self.read_data()
  310.         while m != w and m[0: len(w)] != w:
  311.             m = self.read_data()
  312.  
  313.         return m
  314.  
  315.     def wait_for_service_request(self):
  316.         while True:
  317.             self.read_data(True)
  318.  
  319.             while len(self.sms_queue) > 0:
  320.                 sms = self.read_sms(self.sms_queue[0])
  321.                 self.log('FROM: ' + sms['from'] + '; MSG: ' + sms['content'])
  322.  
  323.                 if sms['content'] == 'WHO AM I?':
  324.                     self.send_sms(sms['from'], sms['from'].replace('+852', ''), pdu=False)
  325.  
  326.                 del self.sms_queue[0]
  327.  
  328.             self.check_signal()
  329.             time.sleep(0.25)
  330.  
  331.     def wait_for_sms(self, f='', pdu=False):
  332.         self.set_sms_mode(pdu)
  333.  
  334.         if f != '':
  335.             self.log('Waiting for SMS from ' + f)
  336.         else:
  337.             self.log('Waiting for SMS')
  338.  
  339.         start_time = time.time()
  340.         while True:
  341.             self.read_data(True)
  342.  
  343.             if len(self.sms_queue) > 0:
  344.                 sms = self.read_sms(self.sms_queue[0], pdu)
  345.                 if f == '' or f == sms['from']:
  346.                     return sms
  347.  
  348.             if time.time() > start_time + 1800:
  349.                 return False
  350.  
  351.             self.check_signal()
  352.             time.sleep(0.25)
  353.  
  354.     def read_sms(self, k, pdu=False):
  355.         self.device.write(('AT+CMGR=' + k + '\r').encode())
  356.         m = self.wait_for_message('+CMGR:')
  357.  
  358.         if pdu is True:
  359.             m = self.read_data()
  360.             received = SmsDeliver(m)
  361.             sender = received.number.replace('+852', '')
  362.             sms_time = received.date
  363.             content = received.text
  364.         else:
  365.             for d in csv.reader([m[7: len(m)]], skipinitialspace=True):
  366.                 sender = d[1].replace('+852', '')
  367.                 sms_time = d[3]
  368.             content = self.read_data()
  369.  
  370.         self.device.write(('AT+CMGD=' + k + '\r').encode())
  371.         self.read_ok_error()
  372.  
  373.         return {
  374.             'from': sender,
  375.             'time': sms_time,
  376.             'content': content
  377.         }
  378.  
  379.     def send_sms(self, to, msg, pdu=False):
  380.         self.set_sms_mode(pdu)
  381.  
  382.         # Code below is for text mode (mode = 1) only!
  383.         to = to.replace('+852', '')
  384.         self.log('Sending "' + msg + '" to ' + to)
  385.         self.device.write(('AT+CMGS="' + to + '"\r').encode())
  386.         self.wait_for_message('>')
  387.         self.device.write((str(msg) + chr(26)).encode())
  388.         self.read_ok_error()
  389.         return
  390.  
  391.     def handle_registration_code(self):
  392.         while True:
  393.             if tasks[self.usb_id] != {}:
  394.                 self.send_sms(IR_PHONE, tasks[self.usb_id]['keyword'], pdu=False)
  395.                 sms = self.wait_for_sms(f=IR_PHONE, pdu=True)
  396.  
  397.                 if sms is not False:
  398.                     conn = persist.connection()
  399.                     cursor = conn.cursor()
  400.  
  401.                     if 'Your registration code is' in sms['content']:
  402.                         registration_code = sms['content'][26:]
  403.  
  404.                         cursor.execute(
  405.                             "UPDATE `reservation` SET `phone_number` = '%s', `registration_code` = '%s', `receive_time` = %s, `update_time` = %s WHERE `id` = %s LIMIT 1" %
  406.                             (
  407.                                 self.sim['phone'],
  408.                                 registration_code,
  409.                                 int(time.time()),
  410.                                 int(time.time()),
  411.                                 tasks[self.usb_id]['reservation_id']
  412.                             )
  413.                         )
  414.                         self.log('Registration code: ' + registration_code)
  415.                     else:
  416.                         # You can request only one registration code every 30 minutes.
  417.                         self.log(sms['content'])
  418.  
  419.                     cursor.execute("UPDATE `device` SET `status` = 'idle' WHERE `id` = '%s' LIMIT 1" % self.usb_id)
  420.                     tasks[self.usb_id] = {}
  421.  
  422.                     cursor.close()
  423.                     conn.close()
  424.                 else:
  425.                     self.log('Timeout! No response!')
  426.  
  427.             self.check_signal()
  428.             time.sleep(1)
  429.  
  430.     def check_signal(self):
  431.         if EXIT_SIGNAL is True:
  432.             print('Terminating ' + str(self.usb_id))
  433.             self.device.close()
  434.             sys.exit(0)
  435.         return
  436.  
  437.     def log(self, message):
  438.         now = datetime.datetime.now().strftime("%H:%M:%S")
  439.         self.queue.put([self.usb_id, '[' + now + '] ' + message])
  440.         return
  441.  
  442.  
  443. class GUI:
  444.     def __init__(self, root, queue, device_count):
  445.         self.queue = queue
  446.         self.windows = []
  447.         root.wm_title('iReserve GSM-Device Monitor')
  448.  
  449.         font = Font(family="Ubuntu", size=12)
  450.  
  451.         for i in range(device_count):
  452.             self.windows.append(Text(root, {
  453.                 'bg': '#000000',
  454.                 'fg': '#FFFFFF',
  455.                 'width': '42',
  456.                 'height': '28',
  457.                 'font': font
  458.             }))
  459.             self.windows[i].grid(row=int(i / 5), column=i % 5)
  460.  
  461.     def log(self):
  462.         while self.queue.qsize():
  463.             try:
  464.                 data = self.queue.get(0)
  465.                 self.windows[data[0]].insert(END, data[1] + '\n')
  466.                 self.windows[data[0]].see("end")
  467.             except:
  468.                 pass
  469.  
  470. class threadedClient:
  471.     def __init__(self, root, device_count):
  472.         self.root = root
  473.         self.queue = queue.Queue()
  474.         self.gui = GUI(root, self.queue, device_count)
  475.  
  476.         for i in range(device_count):
  477.             threads.append(deviceThread(self.queue, i))
  478.             threads[i].start()
  479.             tasks.append({})
  480.  
  481.         sms_tm = sms_task_monitor()
  482.         sms_tm.start()
  483.  
  484.         self.update()
  485.  
  486.     def update(self):
  487.         self.gui.log()
  488.         self.root.after(200, self.update)
  489.  
  490.  
  491. class sms_task_monitor(threading.Thread):
  492.     def __init__(self):
  493.         threading.Thread.__init__(self)
  494.  
  495.     def run(self):
  496.         conn = persist.connection()
  497.  
  498.         while True:
  499.             cursor = conn.cursor()
  500.  
  501.             cursor.execute("SELECT `reservation`.`id`, `device`.`usb_id`, `reservation`.`keyword` FROM `reservation`, `device` WHERE `reservation`.`device_id` > 0 AND `reservation`.`send_time` = 0 AND `reservation`.`deleted` = 0 AND `device`.`id` = `reservation`.`device_id` ORDER BY `reservation`.`id` DESC")
  502.             ts = cursor.fetchall()
  503.             for t in ts:
  504.                 tasks[int(t[1])] = {
  505.                     'reservation_id': t[0],
  506.                     'keyword': t[2]
  507.                 }
  508.  
  509.                 cursor.execute(
  510.                     "UPDATE `reservation` SET `send_time` = '%s', `update_time` = '%s' WHERE `id` = %s LIMIT 1" %
  511.                     (
  512.                         int(time.time()),
  513.                         int(time.time()),
  514.                         t[0]
  515.                     )
  516.                 )
  517.  
  518.             cursor.close()
  519.  
  520.             if EXIT_SIGNAL is True:
  521.                 conn.close()
  522.                 sys.exit()
  523.  
  524.             time.sleep(1)
  525.  
  526.  
  527. def signal_handler(signal, frame):
  528.     print('')
  529.     terminate()
  530.  
  531.  
  532. def terminate():
  533.     print('Closing devices')
  534.  
  535.     global EXIT_SIGNAL
  536.     EXIT_SIGNAL = True
  537.  
  538.     while True:
  539.         if len(threads) == 0:
  540.             break
  541.  
  542.         for thread in threads:
  543.             if not thread.isAlive():
  544.                 threads.remove(thread)
  545.                 break
  546.  
  547.     sys.exit(0)
  548.  
  549.  
  550. if __name__ == "__main__":
  551.     EXIT_SIGNAL = False
  552.     signal.signal(signal.SIGINT, signal_handler)
  553.  
  554.     cfg = ConfigParser()
  555.     cfg.read('config.ini')
  556.  
  557.     MYSQL_HOST = cfg.get('mysql-server', 'remote_host')
  558.     MYSQL_PORT = cfg.getint('mysql-server', 'port')
  559.     MYSQL_USER = cfg.get('mysql-server', 'user')
  560.     MYSQL_PASSWORD = cfg.get('mysql-server', 'password')
  561.     MYSQL_DATABASE = cfg.get('mysql-server', 'database')
  562.     SERVICE_PHONE = cfg.get('service-sim', 'phone')
  563.     IR_PHONE = cfg.get('ireserve', 'phone')
  564.  
  565.     persist = PersistentDB(pymysql, host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, passwd=MYSQL_PASSWORD, db=MYSQL_DATABASE, charset='utf8mb4')
  566.  
  567.     device_count = int(sys.argv[1:][0])
  568.     if device_count <= 0:
  569.         print('Device count must be greater than 0')
  570.         sys.exit(2)
  571.  
  572.     threads = []
  573.     devices = []
  574.     tasks = []
  575.  
  576.     root = Tk()
  577.     root.protocol("WM_DELETE_WINDOW", terminate)
  578.     client = threadedClient(root, device_count)
  579.     root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement