1

Тема: MicroPython на ESP32s: зависання під час GET запиту

Доброго дня.
Маю модуль esp-wroom-32s, із прошитим MicroPython'ом. Ось повний код для розуміння всієї картини:

from machine import Pin
from time import sleep
from sht30 import SHT30 
import gc
import network

try:
    import usocket as socket
except:
    import socket

def http_get(url):
    import socket
    _, _, host, path = url.split('/', 3)
    addr = socket.getaddrinfo(host, 80)[0][-1]
    s = socket.socket()
    s.connect(addr)
    s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
    while True:
        data = s.recv(200)
        if data:
            print(str(data, 'utf8'), end='')
        else:
            break
    s.close()
    
wlan = network.WLAN(network.STA_IF)    
wlan.active(True)


if not wlan.isconnected():
    print('connecting to network...')
    wlan.connect('TP-Link_0A00', '***')
    while not wlan.isconnected():
        pass
print('network config:', wlan.ifconfig())
led = Pin(2, Pin.OUT)

sensor = SHT30()

while True:
  led.value(not led.value())
  v = sensor.measure_int()
  print(v[2], "%")
  print(v[0], "C")
  toSend = "https://somesoneite.ua/someonescript.php?point=H1:" + str(v[2]) + ";T1:" + str(v[0])
  http_get(toSend)
 
  gc.collect()
  F = gc.mem_free()
  A = gc.mem_alloc()
  T = F+A
  P = '{0:.2f}%'.format(F/T*100)
  print ('Total:{0} Free:{1} ({2})'.format(T,F,P))
  s = os.statvfs('//')
  print('{0} MB'.format((s[0]*s[3])/1048576))
  sleep(5)

Після декількох хвилин модуль висне на функції

http_get(url)

, імовірно у рядках:

    s.connect(addr)
    s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))

Справа в тому, що модуль просто висне: не перезавантажується, жодних повідомлень про скидання мікроконтролера watchdog'ом, це не переповнення пам`яті (в коді перевіряю).
Чи хтось стикався із подібною поведінкою даного модуля на MicroPython? Можливо будуть поради або припущення, хочаб в якому напрямку шукати причину?

2 Востаннє редагувалося Torbins (12.08.2021 09:43:01)

Re: MicroPython на ESP32s: зависання під час GET запиту

Ви можете на стороні somesoneite.ua глянути логи? Може просто якийсь захист спрацьовує?
Варто у себе з компа, на дорослому пітоні, запустити цей http_get.
Чому в рядку s.recv(200) таке число? Варто зробити його кратним MTU.
Залежно від тяжкості сторінки, одного gc.collect() в самому кінці може бути не достатньо. Я би смикав його в середині http_get, в циклі кожні N ітерацій. Але загалом на такому залізі краще ганяти мови програмування з ручним керуванням пам'яттю.

Подякували: Sergij1

3

Re: MicroPython на ESP32s: зависання під час GET запиту

https://forum.micropython.org/viewtopic.php?t=2585

кажуть що можна просто

import urequests

response = urequests.get("http://192.168.1.12/get.php?name=444&age=555")
response.close()

4

Re: MicroPython на ESP32s: зависання під час GET запиту

Torbins написав:

Ви можете на стороні somesoneite.ua глянути логи? Може просто якийсь захист спрацьовує?
Варто у себе з компа, на дорослому пітоні, запустити цей http_get.
Чому в рядку s.recv(200) таке число? Варто зробити його кратним MTU.
Залежно від тяжкості сторінки, одного gc.collect() в самому кінці може бути не достатньо. Я би смикав його в середині http_get, в циклі кожні N ітерацій. Але загалом на такому залізі краще ганяти мови програмування з ручним керуванням пам'яттю.

Щодо логів та "дорослого" пайтона - перевірю, дякую за пораду.

5

Re: MicroPython на ESP32s: зависання під час GET запиту

frz написав:

https://forum.micropython.org/viewtopic.php?t=2585

кажуть що можна просто

import urequests

response = urequests.get("http://192.168.1.12/get.php?name=444&age=555")
response.close()

Це також пробував, все одно зависає на стрічці

response = urequests.get("http://192.168.1.12/get.php?name=444&age=555")

Зрештою, якщо не помиляюся, urequests.get() все одно використовує ті ж sockets.

6

Re: MicroPython на ESP32s: зависання під час GET запиту

Саме так, що ж йому ще використовувати? HTTP(S) протокол послуговується сокетами.

7 Востаннє редагувалося koala (14.08.2021 05:42:37)

Re: MicroPython на ESP32s: зависання під час GET запиту

0xDADA11C7 написав:

Саме так, що ж йому ще використовувати? HTTP(S) протокол послуговується сокетами.

Я перепрошую, але сокети - це транспортний рівень, TCP. HTTP(S) - це прикладний рівень і рівень представлення моделі OSI. Тобто в теорії HTTP(S) може працювати і не через сокети, але на практиці іншого шляху немає.

Подякували: 0xDADA11C7, ReAl, leofun013

8

Re: MicroPython на ESP32s: зависання під час GET запиту

Ось, що на сьогодні вже стало відомо. Перевірив всі поради, які тут отримав. На разі таке:
Модуль зависає на стрічці:

data = s.recv(200)

Виглядає так, що мікроконтролер очікує відповіді від ресурса і якщо відповідь від сервера чомусь не приходить від просто собі тупотить на місці.
В якості тимчасового вирішення даної проблеми я вказав таймаут і ловлю виняток. У обробку винятку, я так розумію і потрапляю після спливання таймауту.

while True:
        try:
          s.settimeout(5)
          data = s.recv(1024)
        except:
          print("Timeout on recv(): " )
          break
        if data:
            print(str(data, 'utf8'), end='')
        else:
            break

9

Re: MicroPython на ESP32s: зависання під час GET запиту

Torbins написав:

Ви можете на стороні somesoneite.ua глянути логи? Може просто якийсь захист спрацьовує?
Варто у себе з компа, на дорослому пітоні, запустити цей http_get.

Перевірив. Дорослий пайтон з таким кодом проблем не має. Логи також нічого цікавого не показують.

Подякували: 0xDADA11C71

10

Re: MicroPython на ESP32s: зависання під час GET запиту

Можливо воно просто дуже довго працює, і somesoneite.ua закриває з'єднання по таймауту. Після цього стається таймаут на контролері.
Пограйтеся з розміром s.recv, наприклад зробіть його рівним MTU у вашій мережі. Можна спробувати ще збільшити його.
Крім того, в середині While варто спробувати викликати gc.collect() з певною частотою. Плюс оголошення змінної data можна спробувати винести за цикл.

Подякували: Sergij1