-
Notifications
You must be signed in to change notification settings - Fork 26
/
smsdispatcher.py
160 lines (138 loc) · 5.68 KB
/
smsdispatcher.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from threading import Thread
from queue import Queue, Empty
from redis import Redis
import json, re, time
from datetime import datetime
from sms import SMS, BALANCE_USSD, NetworkStatus
LOGGER="SMSDispatcher"
TEN_MEGABYTES=10485760
FIVE_MINUTES=300.
PORT="/dev/ttyAMA0"
BAUD=9600
def taskWorker():
_redis=Redis()
_redis.set("sim800NetworkStatus", "Unknown")
_redis.set("sim800Balance","0")
_redis.set("sim800RSSI",0)
logger=logging.getLogger(LOGGER)
balanceRegExp=re.compile(r"£(\d){1,2}\.(\d){2}")
try:
sms=SMS(PORT,BAUD,logger=logger)
sms.setup()
if not sms.turnOn():
logger.critical("Failed to turn on SMS!")
return
if not sms.setEchoOff():
logger.critical("Failed to set SMS echo off!")
return
sms.setTime(datetime.now())
netStat="Unknown"
while netStat!="Good":
netStat=sms.getNetworkStatus()
if netStat is not None:
if netStat in (NetworkStatus.RegisteredHome, NetworkStatus.RegisteredRoaming):
netStat="Good"
elif netStat in (NetworkStatus.Searching,): netStat="Searching"
else: netStat="Bad"
else: netStat="Unknown"
_redis.set("sim800NetworkStatus", netStat)
checkBalance=True
statusCheckTime=0.
while True:
if taskQueue.empty():
if checkBalance:
checkBalance=False
balanceMsg=sms.sendUSSD(BALANCE_USSD)
logger.info("Balance message: {}".format(balanceMsg))
match=balanceRegExp.search(balanceMsg)
if match is not None:
balance=match.group(0)
logger.info("Balance amount: {}".format(balance))
_redis.set("sim800Balance",balance)
if (time.time()-statusCheckTime)>FIVE_MINUTES:
rssi=sms.getRSSI()
if rssi is not None: rssi=(rssi.value/4.)*100
else: rssi=0
_redis.set("sim800RSSI",rssi)
netStat=sms.getNetworkStatus()
if netStat is not None:
if netStat in (NetworkStatus.RegisteredHome, NetworkStatus.RegisteredRoaming):
netStat="Good"
elif netStat in (NetworkStatus.Searching,): netStat="Searching"
else: netStat="Bad"
else: netStat="Unknown"
_redis.set("sim800NetworkStatus", netStat)
statusCheckTime=time.time()
try: task=taskQueue.get(timeout=60)
except Empty: continue
if task is None: continue
phoneNumber=task.get('phoneNumber')
message=task.get('message')
if phoneNumber and message:
logger.info("Sending SMS: {}, {}".format(phoneNumber, message))
if sms.sendSMS(phoneNumber, message):
logger.info("SMS sent successfully")
checkBalance=True
else: logger.error("Failed to send SMS! {}, {}".format(phoneNumber, message))
else: logger.error("Task is not valid: {}".format(task))
taskQueue.task_done()
except Exception as e:
logger.critical("Exception in task thread: {}".format(e))
return
def main():
logger=logging.getLogger(LOGGER)
_redis=Redis()
pubsub=_redis.pubsub()
pubsub.subscribe(['sms'])
for msg in pubsub.listen():
if msg['channel']!=b'sms':
logger.debug("Got message unknown channel {}".format(msg['channel']))
continue
if msg['type']=='subscribe':
logger.info("Subscribed to channel")
continue
if msg['type']!='message':
logger.debug("Got unknown message type {}".format(msg['type']))
continue
try:
data=msg['data'].decode('utf-8')
data=json.loads(data)
except Exception as e:
logging.error("Failed to decode data: {}, {}".format(msg['data'], e))
continue
taskQueue.put(data)
if __name__=="__main__":
import sys, logging
from argparse import ArgumentParser
def exceptionHook(etype, evalue, etraceback):
from traceback import format_tb
logger=logging.getLogger(LOGGER)
logstr="{name}; {value}; {traceback}".format(
name=etype.__name__,
value=str(evalue) or "(None)",
traceback="\n".join(format_tb(traceback))
)
logger.critical(logstr)
for h in logger.handlers:
try: h.flush()
except: continue
parser=ArgumentParser(description="SMS Dispatcher.")
parser.add_argument("-d", "--debug", dest="debug", default=False,
action="store_true", help="turn on debug information")
parser.add_argument("-s", "--stdout", dest="stdout", default=False,
action="store_true", help="re-direct logging output to stdout")
options=parser.parse_args()
loglevel=logging.DEBUG if options.debug else logging.WARNING
logger=logging.getLogger(LOGGER)
if options.stdout: handler=logging.StreamHandler(sys.stdout)
else:
from logging.handlers import RotatingFileHandler
handler=RotatingFileHandler("./smsdispatcher.log", maxBytes=TEN_MEGABYTES, backupCount=5)
handler.setFormatter(logging.Formatter("%(asctime)s : %(levelname)s -> %(message)s"))
logger.addHandler(handler)
logger.setLevel(loglevel)
sys.excepthook=exceptionHook
taskQueue=Queue()
taskThread=Thread(target=taskWorker)
taskThread.start()
main()