Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import signal
- from configparser import ConfigParser
- import threading
- import queue
- import datetime
- import serial
- import pymysql
- import csv
- import time
- from tkinter import *
- from tkinter.font import Font
- import sys
- from DBUtils.PersistentDB import PersistentDB
- from messaging.sms import SmsSubmit, SmsDeliver
- class deviceThread(threading.Thread):
- def __init__(self, queue, usb_id):
- threading.Thread.__init__(self)
- self.queue = queue
- self.usb_id = usb_id
- self.sms_pdu_mode = None
- self.service_mode = False
- self.device = serial.Serial('/dev/ttyUSB' + str(self.usb_id), 115200, timeout=0)
- devices.append(self.device)
- self.sim = {
- 'id': '',
- 'iccid': '',
- 'phone': ''
- }
- self.sms_queue = []
- def run(self):
- self.log('USB-' + str(self.usb_id))
- self.network_registration()
- if self.sim['iccid'] == cfg.get('service-sim', 'iccid'):
- self.service_mode = True
- self.device_registration()
- if self.service_mode is True:
- self.log('SERVICE MODE')
- self.wait_for_service_request()
- else:
- self.log('BOT MODE')
- self.handle_registration_code()
- def network_registration(self):
- self.log('Set GSM mode')
- self.device.write('AT+CSCS="GSM"\r'.encode())
- if self.read_ok_error() is False:
- sys.exit(2)
- self.log('Set SMS storage')
- self.device.write('AT+CPMS="SM"\r'.encode())
- if self.read_ok_error() is False:
- sys.exit(2)
- self.log('Clean-up SMS storage')
- self.device.write('AT+CMGD=1,4\r'.encode())
- if self.read_ok_error() is False:
- sys.exit(2)
- self.device.write('AT+CCID\r'.encode()) # check SIM ID
- self.wait_for_message('AT+CCID')
- self.sim['iccid'] = self.read_data()
- self.read_ok_error()
- self.log('ICCID: ' + self.sim['iccid'])
- mii = self.sim['iccid'][0:2]
- if mii != '89':
- self.log('SIM ERROR!')
- sys.exit(2)
- cc = self.sim['iccid'][2:5]
- if cc != '852':
- self.log('Non HK SIM!')
- sys.exit(2)
- mnc = self.sim['iccid'][5:7]
- register_mnc = ''
- if mnc == '00':
- operator = 'HKT GSM900'
- elif mnc == '01':
- operator = 'CITIC MVNO'
- elif mnc == '02':
- operator = 'HKT 3G'
- register_mnc = '00'
- elif mnc == '03':
- operator = 'Hutchison 3G'
- register_mnc = '04'
- elif mnc == '04':
- operator = 'Hutchison GSM900/1800'
- elif mnc == '05':
- operator = 'Hutchison CDMA'
- register_mnc = '04'
- elif mnc == '06':
- operator = 'SmarTone GSM900'
- elif mnc == '07':
- operator = 'China Unicom MVNO'
- elif mnc == '08':
- operator = 'Truphone MVNO'
- elif mnc == '09':
- operator = 'CMMobile MVNO'
- elif mnc == '10':
- operator = 'HKT GSM1800'
- elif mnc == '11':
- operator = 'China-Hongkong Telecom MVNO'
- elif mnc == '12':
- operator = 'China Mobile GSM1800'
- elif mnc == '13':
- operator = 'China Mobile MVNO'
- elif mnc == '14':
- operator = 'Hutchison GSM1800'
- elif mnc == '15':
- operator = 'SmarTone 3G'
- register_mnc = '06'
- elif mnc == '16':
- operator = 'HKT GSM1800'
- elif mnc == '17':
- operator = 'SmarTone GSM1800'
- elif mnc == '18':
- operator = 'HKT GSM1800'
- elif mnc == '19':
- operator = 'HKT 3G'
- elif mnc == '20':
- operator = 'HKT LTE'
- register_mnc = '00'
- elif mnc == '21':
- operator = '21Vianet MVNO'
- elif mnc == '22':
- operator = '263 Mobile'
- elif mnc == '23':
- operator = 'Lycamobile'
- elif mnc == '24':
- operator = 'Multibyte Info Technology'
- elif mnc == '29':
- operator = 'HKT CDMA2000'
- register_mnc = '00'
- elif mnc == '31':
- operator = 'China Telecom MVNO'
- elif mnc == '32':
- operator = 'HKBN MVNO'
- elif mnc == '33':
- operator = 'Tai Tung Mobile MVNO'
- else:
- operator = ''
- if operator != '':
- self.log(operator)
- else:
- self.log('Operator not supported')
- sys.exit(1)
- if register_mnc == '':
- self.device.write('AT+COPS=0\r'.encode())
- else:
- self.log('Manual register to network 454' + register_mnc)
- c = 'AT+COPS=1,2,"454' + register_mnc + '"'
- self.device.write((c + '\r').encode())
- self.wait_for_message(c)
- if self.read_ok_error() is True:
- self.log('Registered on the network')
- conn = persist.connection()
- cursor = conn.cursor()
- cursor.execute(
- "SELECT `id`, `phone` FROM `sim` WHERE `iccid` = '%s'" %
- self.sim['iccid']
- )
- data = cursor.fetchone()
- if data is None:
- self.log('Making a call to activate SIM card')
- self.device.write('ATD1878200;\r'.encode())
- time.sleep(60)
- self.device.write('AT+CHUP\r'.encode())
- self.send_sms(SERVICE_PHONE, 'WHO AM I?', pdu=False)
- sms = self.wait_for_sms(SERVICE_PHONE, pdu=False)
- self.sim['phone'] = sms['content']
- self.log('Phone number is ' + self.sim['phone'])
- cursor.execute(
- "INSERT INTO `sim` (`iccid`, `phone`) VALUES ('%s', '%s')" %
- (
- self.sim['iccid'],
- self.sim['phone']
- )
- )
- conn.commit()
- self.sim['id'] = cursor.lastrowid
- else:
- self.sim['id'] = data[0]
- self.sim['phone'] = data[1]
- self.log("Number from DB: " + self.sim['phone'])
- cursor.close()
- conn.close()
- return
- else:
- self.log('Failed to register')
- sys.exit(2)
- def set_sms_mode(self, pdu=False):
- if pdu is False and self.sms_pdu_mode is not False:
- self.log('Set text mode')
- self.device.write('AT+CMGF=1\r'.encode())
- elif pdu is True and self.sms_pdu_mode is not True:
- self.log('Set PDU mode')
- self.device.write('AT+CMGF=0\r'.encode())
- else:
- return
- self.read_ok_error()
- self.sms_pdu_mode = pdu
- return
- def device_registration(self):
- conn = persist.connection()
- cursor = conn.cursor()
- cursor.execute("SELECT `id` FROM `device` WHERE `usb_id` = '%s'" % self.usb_id)
- data = cursor.fetchone()
- if self.service_mode is True:
- status = 'server'
- else:
- status = 'idle'
- if data is None:
- self.log('Recording device')
- cursor.execute(
- "INSERT INTO `device` (`usb_id`, `sim_id`, `status`) VALUES ('%s', '%s', '%s')" %
- (
- self.usb_id,
- self.sim['id'],
- status
- )
- )
- self.device_id = int(cursor.lastrowid)
- else:
- self.log('Updating device')
- self.device_id = int(data[0])
- cursor.execute(
- "UPDATE `device` SET `sim_id` = '%s', `status` = '%s' WHERE `usb_id` = '%s' LIMIT 1" %
- (
- self.sim['id'],
- status,
- self.usb_id
- )
- )
- conn.commit()
- cursor.close()
- conn.close()
- def read_data(self, return_if_cmd=False):
- buffer = ''
- while True:
- data = self.device.read().decode()
- if data != '':
- if data == '>':
- return '>'
- elif data != "\r" and data != "\n":
- buffer = buffer + data
- elif buffer != '':
- if buffer[0: 11] == '+CMTI: "SM"':
- k = buffer[12:]
- self.sms_queue.append(k)
- if return_if_cmd is True:
- return
- else:
- buffer = ''
- else:
- return buffer
- else:
- self.check_signal()
- time.sleep(0.25)
- def read_ok_error(self):
- m = self.read_data()
- while m != 'OK' and m != 'ERROR':
- m = self.read_data()
- if m == 'OK':
- return True
- else:
- return False
- def wait_for_message(self, w):
- m = self.read_data()
- while m != w and m[0: len(w)] != w:
- m = self.read_data()
- return m
- def wait_for_service_request(self):
- while True:
- self.read_data(True)
- while len(self.sms_queue) > 0:
- sms = self.read_sms(self.sms_queue[0])
- self.log('FROM: ' + sms['from'] + '; MSG: ' + sms['content'])
- if sms['content'] == 'WHO AM I?':
- self.send_sms(sms['from'], sms['from'].replace('+852', ''), pdu=False)
- del self.sms_queue[0]
- self.check_signal()
- time.sleep(0.25)
- def wait_for_sms(self, f='', pdu=False):
- self.set_sms_mode(pdu)
- if f != '':
- self.log('Waiting for SMS from ' + f)
- else:
- self.log('Waiting for SMS')
- start_time = time.time()
- while True:
- self.read_data(True)
- if len(self.sms_queue) > 0:
- sms = self.read_sms(self.sms_queue[0], pdu)
- if f == '' or f == sms['from']:
- return sms
- if time.time() > start_time + 1800:
- return False
- self.check_signal()
- time.sleep(0.25)
- def read_sms(self, k, pdu=False):
- self.device.write(('AT+CMGR=' + k + '\r').encode())
- m = self.wait_for_message('+CMGR:')
- if pdu is True:
- m = self.read_data()
- received = SmsDeliver(m)
- sender = received.number.replace('+852', '')
- sms_time = received.date
- content = received.text
- else:
- for d in csv.reader([m[7: len(m)]], skipinitialspace=True):
- sender = d[1].replace('+852', '')
- sms_time = d[3]
- content = self.read_data()
- self.device.write(('AT+CMGD=' + k + '\r').encode())
- self.read_ok_error()
- return {
- 'from': sender,
- 'time': sms_time,
- 'content': content
- }
- def send_sms(self, to, msg, pdu=False):
- self.set_sms_mode(pdu)
- # Code below is for text mode (mode = 1) only!
- to = to.replace('+852', '')
- self.log('Sending "' + msg + '" to ' + to)
- self.device.write(('AT+CMGS="' + to + '"\r').encode())
- self.wait_for_message('>')
- self.device.write((str(msg) + chr(26)).encode())
- self.read_ok_error()
- return
- def handle_registration_code(self):
- while True:
- if tasks[self.usb_id] != {}:
- self.send_sms(IR_PHONE, tasks[self.usb_id]['keyword'], pdu=False)
- sms = self.wait_for_sms(f=IR_PHONE, pdu=True)
- if sms is not False:
- conn = persist.connection()
- cursor = conn.cursor()
- if 'Your registration code is' in sms['content']:
- registration_code = sms['content'][26:]
- cursor.execute(
- "UPDATE `reservation` SET `phone_number` = '%s', `registration_code` = '%s', `receive_time` = %s, `update_time` = %s WHERE `id` = %s LIMIT 1" %
- (
- self.sim['phone'],
- registration_code,
- int(time.time()),
- int(time.time()),
- tasks[self.usb_id]['reservation_id']
- )
- )
- self.log('Registration code: ' + registration_code)
- else:
- # You can request only one registration code every 30 minutes.
- self.log(sms['content'])
- cursor.execute("UPDATE `device` SET `status` = 'idle' WHERE `id` = '%s' LIMIT 1" % self.usb_id)
- tasks[self.usb_id] = {}
- cursor.close()
- conn.close()
- else:
- self.log('Timeout! No response!')
- self.check_signal()
- time.sleep(1)
- def check_signal(self):
- if EXIT_SIGNAL is True:
- print('Terminating ' + str(self.usb_id))
- self.device.close()
- sys.exit(0)
- return
- def log(self, message):
- now = datetime.datetime.now().strftime("%H:%M:%S")
- self.queue.put([self.usb_id, '[' + now + '] ' + message])
- return
- class GUI:
- def __init__(self, root, queue, device_count):
- self.queue = queue
- self.windows = []
- root.wm_title('iReserve GSM-Device Monitor')
- font = Font(family="Ubuntu", size=12)
- for i in range(device_count):
- self.windows.append(Text(root, {
- 'bg': '#000000',
- 'fg': '#FFFFFF',
- 'width': '42',
- 'height': '28',
- 'font': font
- }))
- self.windows[i].grid(row=int(i / 5), column=i % 5)
- def log(self):
- while self.queue.qsize():
- try:
- data = self.queue.get(0)
- self.windows[data[0]].insert(END, data[1] + '\n')
- self.windows[data[0]].see("end")
- except:
- pass
- class threadedClient:
- def __init__(self, root, device_count):
- self.root = root
- self.queue = queue.Queue()
- self.gui = GUI(root, self.queue, device_count)
- for i in range(device_count):
- threads.append(deviceThread(self.queue, i))
- threads[i].start()
- tasks.append({})
- sms_tm = sms_task_monitor()
- sms_tm.start()
- self.update()
- def update(self):
- self.gui.log()
- self.root.after(200, self.update)
- class sms_task_monitor(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- def run(self):
- conn = persist.connection()
- while True:
- cursor = conn.cursor()
- 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")
- ts = cursor.fetchall()
- for t in ts:
- tasks[int(t[1])] = {
- 'reservation_id': t[0],
- 'keyword': t[2]
- }
- cursor.execute(
- "UPDATE `reservation` SET `send_time` = '%s', `update_time` = '%s' WHERE `id` = %s LIMIT 1" %
- (
- int(time.time()),
- int(time.time()),
- t[0]
- )
- )
- cursor.close()
- if EXIT_SIGNAL is True:
- conn.close()
- sys.exit()
- time.sleep(1)
- def signal_handler(signal, frame):
- print('')
- terminate()
- def terminate():
- print('Closing devices')
- global EXIT_SIGNAL
- EXIT_SIGNAL = True
- while True:
- if len(threads) == 0:
- break
- for thread in threads:
- if not thread.isAlive():
- threads.remove(thread)
- break
- sys.exit(0)
- if __name__ == "__main__":
- EXIT_SIGNAL = False
- signal.signal(signal.SIGINT, signal_handler)
- cfg = ConfigParser()
- cfg.read('config.ini')
- MYSQL_HOST = cfg.get('mysql-server', 'remote_host')
- MYSQL_PORT = cfg.getint('mysql-server', 'port')
- MYSQL_USER = cfg.get('mysql-server', 'user')
- MYSQL_PASSWORD = cfg.get('mysql-server', 'password')
- MYSQL_DATABASE = cfg.get('mysql-server', 'database')
- SERVICE_PHONE = cfg.get('service-sim', 'phone')
- IR_PHONE = cfg.get('ireserve', 'phone')
- persist = PersistentDB(pymysql, host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, passwd=MYSQL_PASSWORD, db=MYSQL_DATABASE, charset='utf8mb4')
- device_count = int(sys.argv[1:][0])
- if device_count <= 0:
- print('Device count must be greater than 0')
- sys.exit(2)
- threads = []
- devices = []
- tasks = []
- root = Tk()
- root.protocol("WM_DELETE_WINDOW", terminate)
- client = threadedClient(root, device_count)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement