внезапная ошибка после исправной работы в течение нескольких часов: максимальная глубина рекурсии превысила ошибку при вызове объекта Python - PullRequest
0 голосов
/ 27 февраля 2020

Я использую arduino для подачи данных через последовательный порт в raspi 4, который затем загружает их на листы Google через API Google.

В течение некоторого времени все работало хорошо, но теперь по неизвестной причине запись остановилась среди ночи. когда я посмотрел на командную строку pycharm, я увидел огромную кучу команд (я не копировал все это, только последний экран):

   File "/home/pi/Downloads/WATER PROJECT/MAIN/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
  File "/home/pi/Downloads/WATER PROJECT/MAIN/lib/python3.7/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
  File "/home/pi/Downloads/WATER PROJECT/MAIN/lib/python3.7/site-packages/urllib3/connectionpool.py", line 672, in urlopen
chunked=chunked,
  File "/home/pi/Downloads/WATER PROJECT/MAIN/lib/python3.7/site-packages/urllib3/connectionpool.py", line 421, in _make_request
six.raise_from(e, None)
  File "<string>", line 3, in raise_from
  File "/home/pi/Downloads/WATER PROJECT/MAIN/lib/python3.7/site-packages/urllib3/connectionpool.py", line 416, in _make_request
httplib_response = conn.getresponse()
  File "/usr/lib/python3.7/http/client.py", line 1321, in getresponse
response.begin()
  File "/usr/lib/python3.7/http/client.py", line 320, in begin
self.headers = self.msg = parse_headers(self.fp)
  File "/usr/lib/python3.7/http/client.py", line 214, in parse_headers
return email.parser.Parser(_class=_class).parsestr(hstring)
  File "/usr/lib/python3.7/email/parser.py", line 68, in parsestr
return self.parse(StringIO(text), headersonly=headersonly)
  File "/usr/lib/python3.7/email/parser.py", line 57, in parse
feedparser.feed(data)
  File "/usr/lib/python3.7/email/feedparser.py", line 176, in feed
self._call_parse()
  File "/usr/lib/python3.7/email/feedparser.py", line 180, in _call_parse
self._parse()
  File "/usr/lib/python3.7/email/feedparser.py", line 256, in _parsegen
if self._cur.get_content_type() == 'message/delivery-status':
  File "/usr/lib/python3.7/email/message.py", line 578, in get_content_type
value = self.get('content-type', missing)
  File "/usr/lib/python3.7/email/message.py", line 471, in get
return self.policy.header_fetch_parse(k, v)
  File "/usr/lib/python3.7/email/_policybase.py", line 316, in header_fetch_parse
return self._sanitize_header(name, value)
  File "/usr/lib/python3.7/email/_policybase.py", line 287, in _sanitize_header
if _has_surrogates(value):
  File "/usr/lib/python3.7/email/utils.py", line 57, in _has_surrogates
s.encode()
RecursionError: maximum recursion depth exceeded while calling a Python object

Process finished with exit code 1

код, который я использую:

import logging
import random
import time
import serial
import os
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime


def init_connection(ser, last_experiment=None):
    """
    This function is used to initialize the connection with google's system.
    :param ser: The reference to the serial object we use to communicate with the ATMega328P
    :param last_experiment: If none - it is a normal experiment but else can be used to continue a running experiment
    :return:
    """
    # Use credentials to create a client to interact with the Google Drive API
    scope = ['https://www.googleapis.com/auth/drive']
    creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
    client = gspread.authorize(creds)

    # Make sure you use the right name here
    spread_sheet = client.open("EXPERIMENTS")
    init_experiment(ser, spread_sheet, last_experiment=last_experiment)


def init_experiment(ser, spread_sheet, last_experiment=None):
    """
    This function is used to initialize the experiment: create a new worksheet for the experiment and set it up.
    :param ser: The reference to the serial object we use to communicate with the ATMega328P
    :param spread_sheet: The spreadsheet of the experiment.
    :param last_experiment: If none - it is a normal experiment but else can be used to continue a running experiment
    :return:
    """
    experiment_time = datetime.now().strftime("%Y%m%d%H%M%S")
    print(spread_sheet.title + "@" + experiment_time)
    logging.log(100, spread_sheet.title + "@" + experiment_time)

    # create new worksheet
    if last_experiment is None:
        worksheet = spread_sheet.add_worksheet(title="experiment@" + experiment_time, rows=10000, cols=15)
    else:
        worksheet = spread_sheet.worksheet(last_experiment[0])
    # add titles
    worksheet.update_acell('A1', 't')
    worksheet.update_acell('B1', 'T_1')
    worksheet.update_acell('C1', 'T_2')
    worksheet.update_acell('D1', 'T_3')
    worksheet.update_acell('E1', 'T_4')
    worksheet.update_acell('F1', 'T_5')
    worksheet.update_acell('G1', 'T_6')
    worksheet.update_acell('H1', 'RH_1')
    worksheet.update_acell('I1', 'RH_2')
    worksheet.update_acell('J1', 'RH_3')
    worksheet.update_acell('K1', 'RH_4')
    worksheet.update_acell('L1', 'RH_5')
    worksheet.update_acell('M1', 'RH_6')
    worksheet.update_acell('N1', 'FLOW')
    worksheet.update_acell('O1', 'WEIGHT')

    print("t, T_1, T_2, T_3, T_4, T_5, T_6, RH_1, RH_2, RH_3, RH_4, RH_5, RH_6, FLOW, WEIGHT")
    logging.log(100, "t, T_1, T_2, T_3, T_4, T_5, T_6, RH_1, RH_2, RH_3, RH_4, RH_5, RH_6, FLOW, WEIGHT")

    # start experiment loop
    if last_experiment is None:
        start_experiment(ser, worksheet=worksheet)
    else:
        start_experiment(ser, worksheet=worksheet, worksheet_row=last_experiment[1])


def start_experiment(ser, worksheet, worksheet_row=2):
    """
    The experiment loop, measure the sensors and update the sheet.
    :param ser: The reference to the serial object we use to communicate with the ATMega328P
    :param worksheet: The specific sheet we edit
    :param worksheet_row: The row we're writing at
    :return:
    """
    print(worksheet_row)
    while True:
        try:
            # get measurements and cell range:
            measurements = get_measurements(ser)
            print("vals=" + str(measurements))
            logging.log(100, "vals=" + str(measurements))
            cell_list = worksheet.range('A' + str(worksheet_row) + ':O' + str(worksheet_row))

            # update in sheets
            for i in range(len(measurements)):
                cell_list[i].value = measurements[i]
            worksheet.update_cells(cell_list, 'USER_ENTERED')

        except Exception as e:
            print(e)
            logging.log(100, e)
            time.sleep(100)
            init_connection(ser, last_experiment=(worksheet.title, worksheet_row))
        # next row and wait for some time
        worksheet_row += 1
        time.sleep(30)


def get_measurements(ser):
    """
    This function measures the sensors of the experiment
    :param ser: The reference to the serial object we use to communicate with the ATMega328P
    :return: Array of the measurement according to this order: t, T_in, T_out, T_aux, RH_in, RH_out,         RH_aux, Flux,WaterLevel
    """
    t = datetime.now().strftime('%d/%m/%Y %H:%M:%S')

    # Here we read the data from the sensors
    T_1 = random.randint(1, 3)
    T_2 = random.randint(1, 10) + 15
    T_3 = random.randint(1, 3) - 5
    T_4 = random.randint(1, 4)
    T_5 = random.randint(1, 10) + 13
    T_6 = random.randint(1, 3) - 7
    RH_1 = random.randint(1, 5) + 55
    RH_2 = random.randint(1, 5) + 40
    RH_3 = random.randint(1, 5) + 50
    RH_4 = random.randint(1, 5) + 53
    RH_5 = random.randint(1, 5) + 42
    RH_6 = random.randint(1, 5) + 51
    FLOW = random.randint(1, 100) + 400
    WEIGHT = random.randint(1, 100) + 5

    data = [ser.read()]
    if data[0] != b'':
        newByte = ser.read()
        while newByte != b'':
            data.append(newByte)
            newByte = ser.read()
        data = b''.join(data)
        data = data.decode("utf-8")
        print('data_read=' + str(data))
        data = data.split('\n')
        list_of_parameters = ['t=', 'T1=', 'RH1=', 'T2=', 'RH2=', 'T3=', 'RH3=', 'T4=', 'RH4=', 'T5=', 'RH5=', 'T6=', 'RH6=', 'FLOW=', 'WEIGHT='] #need to be exactly the same as written in the arduino serial monitor
        for line in data:
          if any(x not in line for x in list_of_parameters):
            data.remove(line)

        data = data[len(data) - 1]        

        print('data=' + str(data))
        data = data.split(' ')
        uptime= (data[0])[data[0].index('=') + 1:]
        T_1= (data[1])[data[1].index('=') + 1:]
        RH_1 = (data[2])[data[2].index('=') + 1:]
        T_2 = (data[3])[data[3].index('=') + 1:]
        RH_2 = (data[4])[data[4].index('=') + 1:]
        T_3 = (data[5])[data[5].index('=') + 1:]
        RH_3 = (data[6])[data[6].index('=') + 1:]
        T_4 = (data[7])[data[7].index('=') + 1:]
        RH_4 = (data[8])[data[8].index('=') + 1:]
        T_5 = (data[9])[data[9].index('=') + 1:]
        RH_5 = (data[10])[data[10].index('=') + 1:]
        T_6 = (data[11])[data[11].index('=') + 1:]
        RH_6 = (data[12])[data[12].index('=') + 1:]
        FLOW = (data[13])[data[13].index('=') + 1:]
        WEIGHT = (data[14])[data[14].index('=') + 1:]

    return t, T_1, T_2, T_3,T_4, T_5, T_6, RH_1, RH_2, RH_3, RH_4, RH_5, RH_6,FLOW,WEIGHT


if __name__ == '__main__':
    logging.basicConfig(filename='logs/experiment@' + datetime.now().strftime("%Y%m%d%H%M%S") +'.log', filemode='w',
                    level=100, format="")
    print('Initializing program')
    logging.log(100, 'Initializing program')

    ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=0.1)
    time.sleep(1)
    print('Serial connection is okay')
    logging.log(100, 'Serial connection is okay')

    init_connection(ser)

Я подозреваю, что источником ошибки являются inte rnet проблемы, но опять же - inte rnet в здании работает нормально. и теперь он тоже работает нормально. кто-нибудь испытывал это или может сказать мне, как решить эту проблему?

спасибо!

1 Ответ

0 голосов
/ 27 февраля 2020

Мне кажется, это проблема с вашим rnet подключением или внутренним модулем. Ничто в исключении не относится конкретно к вашему коду. Не копаясь слишком глубоко в этом, я бы поспорил, что ваш inte rnet некоторое время отключался, а модуль, который вы используете для подключения к API Google, рекурсивно пытался восстановить соединение. Только мои догадки.

...