def _status_comparing(self, model, status): self.model = model self.status = status _path_check(IMG_DIR + r'status/') original_img = IMG_DIR + r'status/{}-{}.bmp'.format( self.model, self.status) compare_img = self.img_path if compare_img is None: return False try: img_new = Image.open(compare_img) img_ori = Image.open(original_img) except FileNotFoundError: log.error('Image File Not Exist') log.debug(traceback.format_exc()) return False h_new = img_new.histogram() h_ori = img_ori.histogram() result = math.sqrt( reduce(operator.add, list(map(lambda a, b: (a - b)**2, h_new, h_ori))) / len(h_ori)) if 0 <= result <= 10: return True else: return False
def answer(self, key: str = 'ok'): r_status = self.check_status('ringing') if r_status is True: r = self.send_cmd('press', key) if r == 200: __ = self.check_status('talking') return 200 else: log.error('There is no call incoming at %s' % self.ip) return 480
def _check_status(self, status, param, *args): self.status = status self._prepare_check_status(self.status, param) r = self.request_get(self.url) print(self.url) if r[0] == 200: pat_return_result = r'(?<=<Return>)(\d)(?=</Return>)' check_result = re.findall(pat_return_result, r[1]) if check_result[0] == '0': log.info('{} Status [{}] check passed by Action URL.'.format( self.ip, self.status)) return True elif check_result[0] == '1': log.error('{} Status [{}] check failed by Action URL. ' 'Will try to query OCR'.format(self.ip, self.status)) if self._query_status(param, self.status, args): log.info('{} Status [{}] check passed by OCR.'.format( self.ip, self.status)) return True else: log.error('{} Status [{}] check failed by OCR.'.format( self.ip, self.status)) return False else: log.error('Unknown Event [{}]'.format(check_result)) return False else: log.error( 'Check Status [{}] Error, return code [{}], reason [{}].'. format(self.status, r[0], r[1])) return r[0]
def dial(self, dst): log.info('%s trying to dial %s...' % (self.ext, dst.ext)) r = self.send_cmd('dial', dst) if r == 200: # sleep for 1s to wait for the phone finished the last operation time.sleep(1) r_status = self.check_status('outgoing') if r_status is True: log.info('%s dial %s completed.' % (self.ext, dst.ext)) return 200 else: log.error('%s dial %s failed.' % (self.ext, dst.ext)) return 480 else: return r
def _query_parsing(self, status, model, path, *args): """ Query baidu OCR or Query img comparing. :param status: status for query :return: True or False """ import random self.status = status self.model = model tmp_path = IMG_DIR + r'cropped/tmp-{}{}.bmp'.format( self.status, random.randint(1, 1000)) _path_check(IMG_DIR + 'cropped') # crop img according to query status # if status is 'outgoing', compare result of ocr with dst.ext if self.status == 'outgoing': pixel_tuple = get_phone_pixel(self.model, 'outgoing') crop_img = Image.open(path) try: cropped = crop_img.crop(pixel_tuple) cropped.save(tmp_path) log.info('Pixel tuple is ({})'.format(pixel_tuple)) except ValueError: log.error('Value Error: Pixel tuple need 4 elements.') return False # if status is 'ringing', compare img ringing with specification model elif self.status == 'ringing': pass # if status is 'talking', compare img talking with specification model elif self.status == 'talking': pass # query ocr and compare if there is returning a result if self.status in ('outgoing', ): log.info('Query OCR using img at {}...'.format(tmp_path)) ocr = self._query_ocr(tmp_path) print(ocr) for item in args: if item in ocr: log.info('OCR comparing [{}] with [{}]success.'.format( item, ocr)) return True else: return False
def post_ocr(url, data, header, token): url = url + "?access_token=" + token response = requests.post(url, data=data, headers=header) if response: r = response.json() print(r) try: for __ in r['words_result']: ocr_list.append(__['words']) return ocr_list except KeyError: for k, v in r.items(): if k == 'error_code': if v == 110: log.error( 'Access token invalid or no longer valid.') log.error('Try to update Access token.') return None return None
def get_access_token(*method): access_token = None if len(method) != 0: if method[0] == 'new': ak = 'ljwII9uBaQDdQ3aDfygoywRX' sk = '4iqvryHIdQhOZMtfiAIM27xwjxO0ErlZ' host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=' \ 'client_credentials&client_id=%s&client_secret=%s' % (ak, sk) with open(r'../ext/access_token.json', 'w', encoding='utf-8') as f: response = requests.get(host) if response: json.dump(response.json(), f) with open('../ext/access_token.json', 'r', encoding='utf-8') as f: r = json.load(f) for k, v in r.items(): if k == 'access_token': access_token = v log.info('Access Token found => [{}]'.format(v)) break elif k == 'error_description' or k == 'Client authentication failed': log.error('Access Token Error [{}}]'.format(v)) return None else: continue else: log.error('Access Token or Expires not found, need to check.') if access_token is not None: return access_token else: log.error('Access Token not found, need to check.') return None
def _query_status(self, param, status, *args): print(param) self.ip = param['ip'] self.web_usr = param['web_usr'] self.web_pwd = param['web_pwd'] self.model = param['model'] self.status = status if self.model is None: log.error('Model of {} is None, cannot comparing...'.format( self.ip)) return False else: self.path = self._prepare_img() if self.path is not None: if self._query_parsing(self.status, self.model, self.path, args) is True: return True else: return False else: log.error('Capture screen failed on {}.'.format(self.ip))
def _send_cmd(self, cmd, *args): """ Receive args from :class:`Phone`, call the corresponding method splice them to a completed URL, and call :class:`Request` to send requests.get(). :param cmd: command :str: which action the phone want to call :param *args: given by :class:`Phone` :method:`send_cmd`, contains two part: => obj :obj: it depends on the cmd. For method dial, it is the destination Phone; for method press_key, it is the key will press. => param :dict: phone's property. they all used to splice the HTTP GET URL :return: Return the response of HTTP GET 200 -> success 403 -> Auth Failed 404 -> Not Found 480 -> Local Error 481 -> Remote Error 500 -> Connection Error """ if len(args) == 2: self._prepare_prefix(args[1]) elif len(args) == 1: self._prepare_prefix(args[0]) print(args[0]) if cmd == 'dial': self._prepare_dial(args[0], args[1]) elif cmd == 'press': self._prepare_press(args[0].upper(), args[1]) else: self.url = None r = self.request_get(self.url)[0] if r == 200: log.debug('Send cmd({}) [{}] successfully.'.format( cmd.title(), self.url)) return 200 elif r == 403: log.error( '{} Auth Failed, please check if web_usr and web_pwd are wrong.' .format(self.ip)) return 403 elif r == 404: log.error( '{} Web page not found, please check if url is wrong => [{}]'. format(self.ip, self.url)) elif r == 500: if not self.ping(self.ip): log.error('{} Connection Error. Maybe it is dead.'.format( self.ip)) return 500 else: log.error( '{} Web service error, although the ip can still connect, please check.' .format(self.ip)) return 480 else: log.error('Undefined Return Code [{}]'.format(r)) return r
def _format_check(*arg, arg_type, ): """ Check the legality of the arg according to the arg_type :param *arg: the argument need to be checked :param arg_type: the type of the argument :return: True or False """ if arg_type.upper() == 'IP': if len(arg) != 1: log.error('IP checking accept only 1 ip address.') return False else: _arg = arg[0] try: _ip = _arg.split(r'.') if len(_ip) == 4: pass else: return False if 0 < int(_ip[0]) < 255: pass else: return False for __ in _ip[1:]: if 0 <= int(__) < 255: continue else: return False else: return True except AttributeError: log.error('Argument should be <str `ip`>, not %s' % type(_arg)) return False elif arg_type.upper() == 'EXT': # Extension should be number or SIP URI, so there is currently no too strict check. # But it is still need to protect this argument not to be None if len(arg) == 1: if arg[0] is None: log.error('Argument should be a number or a SIP URI, not %s' % arg) return False else: # TODO: judgment for URI format return True else: log.error('Too many Argument.') return False elif arg_type.upper() == 'LINE': # Compare line to lines, the line should less than or equal to lines # It is ok if lines is int, although it should less than 17 for now, but # it maybe change to larger further. if len(arg) != 2: if (isinstance(arg[0], tuple) or isinstance(arg[0], list)) and len(arg) == 1: if len(arg[0]) != 2: log.error('Line checking accept line(which line) and lines(total number of line), \n\t' 'you can use a tuple or a list to recognize them, or use them 2 directly like:\n\t' '_format_check(line, lines, arg_type=\'line\').') return False else: _line, _lines = arg[0] else: log.error('Line checking only accept a tuple or list contain line and lines, or just them 2.') return False else: _line, _lines = arg if isinstance(_line, int) and isinstance(_lines, int): # _line > 0 and _line <= _lines => _lines > 0 if (_line <= _lines) and _line > 0: return True else: log.error( 'Value of argument `line` must larger than 0 and less than lines({}), ' 'but you give {}.'.format(_lines, _line)) return False elif isinstance(_line, int) and isinstance(_lines, type(None)): # It is ok if _lines is None (if model is not defined, it is None) if 0 < _line <= 16: return True else: log.error( 'Value of argument `line` must larger than 0 and less than or equal to 16, ' 'but you give {}'.format(_line)) return False else: log.error('Type of argument `line` should be :int:, but you give {}'.format(type(_line))) return False