def __start_heartbeat_thread(self, fd): heartbeat_thread = RepeatedTimer(30, self.activetest, args=(fd,)) self.heartbeat_threads[fd] = heartbeat_thread heartbeat_thread.start() logging.info("[SI]%s:%s Heartbeat thread is running...", self.addresses[fd][0], self.addresses[fd][1])
def notify_report_by_push(self, report, mobile): flag = self.check_timestamp(int(report['timestamp'])) if not flag: return name = QueryHelper.get_alias_by_tid(report.dev_id, self.redis, self.db) report.comment = '' region_id = None if report.rName == EVENTER.RNAME.POWERLOW: if report.terminal_type == "1": if int(report.pbat) == 100: report.comment = ErrorCode.ERROR_MESSAGE[ErrorCode.TRACKER_POWER_FULL] elif int(report.pbat) <= 5: report.comment = ErrorCode.ERROR_MESSAGE[ErrorCode.TRACKER_POWER_OFF] else: if int(report.pbat) <= 20: report.comment = (ErrorCode.ERROR_MESSAGE[ErrorCode.TRACKER_POWER_LOW]) % report.pbat else: report.comment = ErrorCode.ERROR_MESSAGE[ErrorCode.FOB_POWER_LOW] % report.fobid elif report.rName in (EVENTER.RNAME.REGION_ENTER, EVENTER.RNAME.REGION_OUT): region = report['region'] region_id = region.region_id if region.get('region_name', None): region.comment = u"围栏名:%s" % safe_unicode(region.region_name) # push if report.rName == EVENTER.RNAME.STOP: logging.info("[EVENTER] %s altert needn't to push to user. Terminal: %s", report.rName, report.dev_id) else: self.notify_to_parents(name, report, mobile, region_id) if report.rName in [EVENTER.RNAME.ILLEGALMOVE, EVENTER.RNAME.ILLEGALSHAKE]: _date = datetime.datetime.fromtimestamp(int(report['timestamp'])) _seconds = _date.hour * 60 * 60 + _date.minute * 60 + _date.second if _seconds < 7 * 60 * 60 or _seconds > 19 * 60 * 60: _resend_alarm = functools.partial(self.notify_to_parents, name, report, mobile, region_id) # 30 seconds later, send sms 1 time. task = RepeatedTimer(30, _resend_alarm, 1) task.start() self.push_to_client(report)
def notify_report_by_sms(self, report, mobile): flag = self.check_timestamp(int(report['timestamp'])) if not flag: return name = QueryHelper.get_alias_by_tid(report.dev_id, self.redis, self.db) terminal_time = get_terminal_time(int(report['timestamp'])) terminal_time = safe_unicode(terminal_time) report_name = report.name if not report_name: if report.cLon and report.cLat: report_name = ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE] else: report_name = ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED] sms = '' sms_white = '' if isinstance(report_name, str): report_name = report_name.decode('utf-8') report_name = unicode(report_name) if report.rName == EVENTER.RNAME.POWERLOW: if report.terminal_type == "1": # type: terminal if int(report.pbat) == 100: pbat_message_key = get_pbat_message_key(report.dev_id) if self.redis.exists(pbat_message_key) is False: self.redis.setvalue(pbat_message_key, 1, time=24*60*60) else: logging.info("[EVENTER] Don't send duplicate power full message to terminal:%s in 24 hours", report.dev_id) return elif int(report.pbat) > 20 and int(report.pbat) < 100: logging.info("[EVENTER] Terminal:%s reported power low pbat:%s between 20% and 100%, so skip it", report.dev_id, report.pbat) return sms = self.handle_power_status(report, name, report_name, terminal_time) else: # type: fob sms = SMSCode.SMS_FOB_POWERLOW % (report.fobid, terminal_time) elif report.rName == EVENTER.RNAME.ILLEGALMOVE: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_ILLEGALMOVE_NOLOC % (name, terminal_time) else: sms = SMSCode.SMS_ILLEGALMOVE % (name, report_name, terminal_time) _date = datetime.datetime.fromtimestamp(int(report['timestamp'])) _seconds = _date.hour * 60 * 60 + _date.minute * 60 + _date.second if _seconds < 7 * 60 * 60 or _seconds > 19 * 60 * 60: _resend_alarm = functools.partial(self.sms_to_user, report.dev_id, sms+u"重复提醒,如已收到,请忽略。", mobile) #NOTE: re-notify # 30 seconds later, send sms 1 time. task = RepeatedTimer(30, _resend_alarm, 1) task.start() elif report.rName == EVENTER.RNAME.ILLEGALSHAKE: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_ILLEGALSHAKE_NOLOC % (name, terminal_time) else: sms = SMSCode.SMS_ILLEGALSHAKE % (name, report_name, terminal_time) #NOTE: re-notify _date = datetime.datetime.fromtimestamp(int(report['timestamp'])) _seconds = _date.hour * 60 * 60 + _date.minute * 60 + _date.second if _seconds < 7 * 60 * 60 or _seconds > 19 * 60 * 60: _resend_alarm = functools.partial(self.sms_to_user, report.dev_id, sms+u"此条短信为重复提醒,请注意您的车辆状态。", mobile) # 30 seconds later, send sms 1 time. task = RepeatedTimer(30, _resend_alarm, 1) task.start() elif report.rName == EVENTER.RNAME.EMERGENCY: whitelist = QueryHelper.get_white_list_by_tid(report.dev_id, self.db) if whitelist: white_str = ','.join(white['mobile'] for white in whitelist) if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_SOS_OWNER_NOLOC % (name, white_str, terminal_time) sms_white = SMSCode.SMS_SOS_WHITE_NOLOC % (name, terminal_time) else: sms = SMSCode.SMS_SOS_OWNER % (name, white_str, report_name, terminal_time) sms_white = SMSCode.SMS_SOS_WHITE % (name, report_name, terminal_time) else: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_SOS_NOLOC % (name, terminal_time) else: sms = SMSCode.SMS_SOS % (name, report_name, terminal_time) elif report.rName == EVENTER.RNAME.POWERDOWN: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_POWERDOWN_NOLOC % (name, terminal_time) else: sms = SMSCode.SMS_POWERDOWN % (name, report_name, terminal_time) elif report.rName == EVENTER.RNAME.REGION_OUT: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_REGION_OUT_NOLOC % (name, safe_unicode(report['region']['region_name']), terminal_time) else: sms = SMSCode.SMS_REGION_OUT % (name, safe_unicode(report['region']['region_name']), report_name, terminal_time) elif report.rName == EVENTER.RNAME.REGION_ENTER: if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_REGION_ENTER_NOLOC % (name, safe_unicode(report['region']['region_name']), terminal_time) else: sms = SMSCode.SMS_REGION_ENTER % (name, safe_unicode(report['region']['region_name']), report_name, terminal_time) elif report.rName == EVENTER.RNAME.SPEED_LIMIT: sms_dct = dict(name=name, report_name=report_name, speed=int(report.get('speed',0)), terminal_time=terminal_time) if report_name in [ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_NAME_NONE], ErrorCode.ERROR_MESSAGE[ErrorCode.LOCATION_FAILED]]: sms = SMSCode.SMS_SPEED_LIMIT_NOLOC % sms_dct else: sms = SMSCode.SMS_SPEED_LIMIT % sms_dct else: pass #wap_url = 'http://api.map.baidu.com/staticimage?center=%s,%s%26width=800%26height=800%26zoom=17%26markers=%s,%s' #wap_url = wap_url % (report.lon/3600000.0, report.lat/3600000.0, report.lon/3600000.0, report.lat/3600000.0) #wap_url = 'http://api.map.baidu.com/staticimage?center=' +\ # str(report.cLon/3600000.0) + ',' + str(report.cLat/3600000.0) +\ # '&width=320&height=480&zoom=17&markers=' +\ # str(report.cLon/3600000.0) + ',' + str(report.cLat/3600000.0) if report.cLon and report.cLat: clon = '%0.3f' % (report.cLon/3600000.0) clat = '%0.3f' % (report.cLat/3600000.0) url = ConfHelper.UWEB_CONF.url_out + '/wapimg?clon=' + clon + '&clat=' + clat tiny_id = URLHelper.get_tinyid(url) if tiny_id: base_url = ConfHelper.UWEB_CONF.url_out + UWebHelper.URLS.TINYURL tiny_url = base_url + '/' + tiny_id logging.info("[EVENTER] get tiny url successfully. tiny_url:%s", tiny_url) self.redis.setvalue(tiny_id, url, time=EVENTER.TINYURL_EXPIRY) sms += u"点击" + tiny_url + u" 查看定位器位置。" if sms_white: sms_white += u"点击" + tiny_url + u" 查看定位器位置。" self.sms_to_whitelist(sms_white, whitelist) else: logging.info("[EVENTER] get tiny url failed.") else: logging.info("[EVENTER] location failed.") self.sms_to_user(report.dev_id, sms, mobile)
class AgpsServer(object): def __init__(self, conf_file): ConfHelper.load(conf_file) self.redis = MyRedis() self._socket = None self.get_agps_thread = None def start(self): self.__start_get_agps_thread() try: self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.bind((ConfHelper.AGPS_CONF['host'], int(ConfHelper.AGPS_CONF['port']))) self._socket.listen(int(ConfHelper.AGPS_CONF['count'])) while True: try: infds, _, _ = select.select([self._socket,],[],[],1) if len(infds) > 0: connection, address = self._socket.accept() data = connection.recv(1024) logging.info("[AGPS] Recv %d length request:\n%s", len(data), data) agps_data = self.handle_request(data) if agps_data: connection.send(agps_data) logging.info("[AGPS] Send response length:%s", len(agps_data)) connection.close() except KeyboardInterrupt: logging.error("[AGPS] Ctrl-C is pressed.") self._socket.close() except: logging.exception("[AGPS] Socket exception.") finally: try: self._socket.close() except: logging.exception("[AGPS] Socket close exception") def handle_request(self, data): try: packet = T_CLWCheck(data) command = packet.head.command if command == GATEWAY.T_MESSAGE_TYPE.AGPS: head = packet.head body = packet.body args = DotDict(success=GATEWAY.RESPONSE_STATUS.SUCCESS, agps_data=None) ap = AgpsParser(body, head) agps_sign = self.get_agps_sign(ap.ret, int(head.timestamp)) if agps_sign != int(head.agps_sign, 16): args.success = GATEWAY.RESPONSE_STATUS.INVALID_SESSIONID logging.error("[AGPS] agps_sign invalid.") else: agps = ap.ret args.agps_data = self.get_agps_from_redis(agps) if args.agps_data: ac = AgpsComposer(args) return ac.buf else: logging.error("[AGPS] there's no invalid agps data.") return None except: logging.exception("[AGPS] Handle agps request exception.") return None def get_agps_sign(self, agps, timestamp): DEFAULT_KEY = 181084178 lon = int(agps.lon) lat = int(agps.lat) agps_sign = DEFAULT_KEY ^ lon ^ lat ^ timestamp return agps_sign def get_agps_from_ublox(self): LON_LAT = GATEWAY.LON_LAT for key, lon_lat in LON_LAT.items(): u_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: request = "cmd=aid;user=%s;pwd=%s;lat=%s;lon=%s;pacc=%s\n" % ( ConfHelper.UBLOX_CONF.user, ConfHelper.UBLOX_CONF.pwd, lon_lat[1], lon_lat[0], ConfHelper.UBLOX_CONF.pacc) u_socket.connect((ConfHelper.UBLOX_CONF.host, int(ConfHelper.UBLOX_CONF.port))) u_socket.send(request) agps_data = self.recv_ublox(u_socket) agps_key = get_agps_data_key(key) if agps_data: self.redis.set(agps_key, base64.b64encode(agps_data)) logging.info("[AGPS] Get agps data [%s] from ublox success.", key) else: self.redis.delete(agps_key) logging.info("[AGPS] Get agps data [%s] from ublox faild.", key) except: logging.exception("[AGPS] Get agps from u-blox exception.") finally: try: u_socket.close() except: logging.exception("[AGPS] U-blox socket close exception.") time.sleep(10) def recv_ublox(self, u_socket): default_length = 1024 split_str = ("\r\n\r\n") agps_data = u_socket.recv(default_length) head = agps_data.split(split_str)[0] binary_length = int(head.split("\n")[1].split(": ")[1]) logging.info("[AGPS] agps_data length:%d", binary_length) remain_length = binary_length - (default_length - (len(head) + len(split_str))) while remain_length: agps_buf = u_socket.recv(remain_length) if not agps_buf: logging.warn("[AGPS] recv empty response of socket!") u_socket.close() raise socket.error(errno.EPIPE, "the pipe might be broken.") agps_data += agps_buf remain_length -= len(agps_buf) return agps_data[-binary_length:] def get_agps_from_redis(self, agps): try: logging.info("[AGPS] Terminal lon=%s, lat=%s", agps.lon, agps.lat) partition_key = self.get_partition_key(float(agps.lon), float(agps.lat)) agps_key = get_agps_data_key(partition_key) agps_data = self.redis.get(agps_key) agps_data = agps_data if agps_data else "" return agps_data except: logging.exception("[AGPS] Get agps from redis exception.") return "" def get_partition_key(self, lon, lat): LON_LAT = GATEWAY.LON_LAT partition_key = "default" for key, lon_lat in LON_LAT.items(): if abs(float(lon_lat[0]) - lon / 3600000) <= 10 and \ abs(float(lon_lat[1]) - lat / 3600000) <= 12.5: partition_key = key break logging.info("[AGPS] agps partition is:%s", partition_key) return partition_key def __start_get_agps_thread(self): self.get_agps_thread = RepeatedTimer(int(ConfHelper.UBLOX_CONF.interval), self.get_agps_from_ublox) self.get_agps_thread.start() logging.info("[AGPS] Get agps thread is running...") def __stop_get_agps_thread(self): if self.get_agps_thread is not None: self.get_agps_thread.cancel() self.get_agps_thread.join() logging.info("[AGPS] Get agps thread stop.") self.get_agps_thread = None def stop(self): self.__stop_get_agps_thread() self._socket.close()