1

Context

I have a Pycom WiPy board running some Python code. The code makes a HTTP Post request to a .NET web API using _urequest module.

Problem

When the HTTP Post request is sent, a [Errno 202] EAI_FAIL exception is thrown. This happens several times after one after the other, since the request is sent every 10 seconds in a loop.

Code

Wifi Client, connects to the local wifi and gains internet access

import json
import time
from network import WLAN

# Wifi client singleton
wifiClient = None

def initWifiClient():
    global wifiClient
    wifiClient = WifiClient()

def getWifiClient():
    global wifiClient
    return wifiClient

class WifiClient:

    wifi = None
    lastWifiConnectAttempt = None

    def __init__(self):
        self.wifi = WLAN(mode=WLAN.STA)
        pass

    def connect(self):
        if not self.__readyForNewWifiConnectAttempt():
            print("Not ready yet for new WIFI connect attempt.")
            self.__printSecondsLeftToNextConnectAttempt()
            return

        print("Trying to connect WIFI.")
        try:
            self.lastWifiConnectAttempt = time.time()
            with open('wifi.json') as json_file:
                wifiJson = json.load(json_file)

                self.wifi.connect(ssid=wifiJson['ssid'], auth=(WLAN.WPA2, wifiJson['password']), timeout=30000)

                # Add connection timeout handler to prevent timeout exception crash.
                self.wifi.callback(WLAN.SMART_CONF_TIMEOUT, handler=self.__onWifiConnectTimeout)

                pass
        except Exception as e:
            self.lastWifiConnectAttempt = None
            print (e)
            pass

    def __readyForNewWifiConnectAttempt(self):
        if self.lastWifiConnectAttempt == None:
            return True
        
        return (time.time() - self.lastWifiConnectAttempt) > 42

    def __onWifiConnectTimeout(self, args):
        self.lastWifiConnectAttempt = None
        pass

    # For debugging
    def __printSecondsLeftToNextConnectAttempt(self):
        secondsLeft = 43 - (time.time() - self.lastWifiConnectAttempt)
        if secondsLeft < 0:
            secondsLeft = 0

        print("Seconds left to be ready for next WIFI connect attempt: " +  str(secondsLeft))


Web api caller/client code, helper module for sending different calls to the web api:

This mdoule runs the background work loop which makes the api call and catches the [Errno 202] EAI_FAIL exception.

from machine import Timer
from hardware import web, unit
from events import commands as cmd
from util import weblog
import ujson
import pycom
import gc
from hardware.wifi_client import getWifiClient

# globals for this file
_background_timer = None
_background_app = None



def get_client():
  client = web.Client()
  client.base_url = "..."
  # client.base_url = "..."
  return client

def send_data(): 
  print ("sending data")
  client = get_client()

  client.headers['Content-Type'] = 'application/json'

  # client.headers['Accept'] = '*/*'
  # client.headers['User-Agent'] = 'PostmanRuntime/7.28.4'
  # client.headers['Host'] = '...'
  # client.headers['Connection'] = 'keep-alive'

  p = cmd.Measure()

  data = {
    'uuid' : unit.ID,
    'value' : round(p, 1),
    'measured': "1970-01-01T00:00:00.000Z"
  }

  response = client.post('ApiMethod', data)
  print (response.text)
  pass


def background_work(o):
  global _background_app
  global wifiClient

  try:
    pycom.rgbled(0)
    gc.collect()

    mfree = gc.mem_free()

    print ("Memfree: " + str(mfree))
    if (getWifiClient().wifi.isconnected()):

      if (mfree < 1000000):
        weblog.warning("Memory low: %d", mfree)
        print("Memory low: %d", mfree)

      send_data()
    
      app = _background_app
      fetch_data(app)
      pycom.rgbled(0x002f00)
       
    else:
      pycom.rgbled(0x2F)
      print ("Not connected to WIFI")
      getWifiClient().connect()

  except Exception as e:
    pycom.rgbled(0x2f0000)
    print("send exception")
    print(e)
    
    pass
  pass

def stop_background():
  global _background_timer
  
  if _background_timer:
    _background_timer.cancel()
    _background_timer = None

  pass

def start_background(app):
  global _background_timer, _background_app

  stop_background()

  _background_app = app
  _background_timer = Timer.Alarm(background_work, s=10, periodic=True)
  pass

HTTP client, makes the HTTP calls to the api:

import _urequest as ureq


class Client:

  def __init__(self):
    self.headers = {}
    self.base_url = ""
    pass

  ...

  def post(self, url, payload):
    print(self.base_url)
    print(self.base_url + url)
    return ureq.post(self.base_url + url, headers = self.headers, json = payload)

  ...

  def base(self, url):
    self.base_url = url

Console outpus

sending data
send exception
[Errno 202] EAI_FAIL
Memfree: 2527712
sending data
send exception
[Errno 202] EAI_FAIL
Memfree: 2527712
sending data

Question

Why is the [Errno 202] EAI_FAIL exception thrown?

Thanks!

EggBender
  • 888
  • 15
  • 36

1 Answers1

0

Looks like it's related to the DNS as stated in this answer to a forum post:

The EAI_FAIL is related to not being able to resolve the DNS.

It looks like it a Pycom specific error code rooted in the getaddrinfo() function (another forum post). You'll also find it mentioned briefly in the LTE docs (scoll down to "Pycom simcards" section)

I'm guessing this gets called when you set client.base_url? TBH, I don't recognise some of your imports from the Pycom docs.

goldfishalpha
  • 447
  • 2
  • 4
  • 13