EHOSTUNREACH With PyCom AWS Tutorial


  • Pybytes Beta

    I'm following the PyCom AWS Tutorial but am running into a EHOSTUNREACH error on the MQTT connect step.

    I've verified my certs and host using a different MQTT client on the same network. When I call the run function from demo.py, it will hang in the connection loop. The first iteration will fail with "[Errno 113] EHOSTUNREACH". The rest fail with either an OSError: -32512 or OSError: 23


  • Pybytes Beta

    @gertjanvanhethof

    The '.pem' is more a convention in my office of labeling all certificate related files with that file type. It is the rootCA certificate.

    I've been able to use the same certificate files to connect to AWS MQTT via a desktop client, so it shouldn't be an issue on the cloud side.


  • Pybytes Beta

    No it should be something else.
    Try to make a connection to AWS using CLI and python library from a laptop.
    Probably it's a security issue. I'am getting the same error now.
    Give me some time, I will try to get it working and tell you how I solved it.


  • Pybytes Beta

    @noobiemcfoob

    In you code I see: ca_certs='/flash/cert/rootCA.pem'
    I think this should be a cert file and not the rootCA.pem.

    Besides this, do you really have a rootCA.pem instead of a rootCA.crt?


  • Pybytes Beta

    @gertjanvanhethof :
    Here's demo.py

    import time
    from mqttclient import MQTTClient
    
    DISCONNECTED = 0
    CONNECTING = 1
    CONNECTED = 2
    DEVICE_ID = "12345"
    HOST = "a33wjx7cetm2t9.iot.us-east-1.amazonaws.com"
    TOPIC_DOWNLOAD = "Download"
    TOPIC_UPLOAD = "Upload"
    
    
    state = DISCONNECTED
    connection = None
    
    def _recv_msg_callback(topic, msg):
        print("Received: {} from Topic: {}".format(msg, topic))
    
    def _send_msg(msg):
        global connection
        connection.publish(TOPIC_UPLOAD, msg)
    
    def run():
        global state
        global connection
    
        while True:
            # Wait for connection
            while state != CONNECTED:
                try:
                    state = CONNECTING
                    connection = MQTTClient(DEVICE_ID, server=HOST, port=8883)
                    connection.connect(ssl=True, certfile='/flash/cert/certificate.key', keyfile='/flash/cert/private.key', ca_certs='/flash/cert/rootCA.pem')
                    state = CONNECTED
                except Exception as e:
                    print('Error connecting to the server: {}'.format(e))
                    time.sleep(0.5)
                    continue
    
            print('Connected!')
    
            # Subscribe for messages
            connection.set_callback(_recv_msg_callback)
            connection.subscribe(TOPIC_DOWNLOAD)
    
            while state == CONNECTED:
                connection.check_msg()
                msg = '{"Name":"Pycom", "Data":"Test"}'
                print('Sending: ' + msg)
                _send_msg(msg)
                time.sleep(2.0)
    

    and mqttclient:

    import socket
    import struct
    import select
    from binascii import hexlify
    
    
    class MQTTException(Exception):
        pass
    
    
    class MQTTClient:
        def __init__(self, client_id, server, port=1883, user=None, password=None):
            self.client_id = client_id.encode('utf8')
            self.sock = None
            self.addr = socket.getaddrinfo(server, port)[0][-1]
            self.pid = 0
            self.cb = None
            self.poll = select.poll()
            self.__will_message = None
            if user:
                self.__user = user.encode('utf8')
            else:
                self.__user = None
            self.__password = password
    
        def __encode_varlen_length(self, length):
            i = 0
            buff = bytearray()
            while 1:
                buff.append(length % 128)
                length = length // 128
                if length > 0:
                    buff[i] = buff[i] | 0x80
                    i += 1
                else:
                    break
    
            return buff
    
        def __encode_16(self, x):
            return struct.pack("!H", x)
    
        def __pascal_string(self, s):
            return struct.pack("!H", len(s)) + s
    
        def __recv_varlen_length(self):
            m = 1
            val = 0
            while 1:
                b = self.sock.recv(1)[0]
                val += (b & 0x7F) * m
                m *= 128
                if m > 2097152: # 128 * 128 * 128
                    raise MQTTException()
                if (b & 0x80) == 0:
                    break
            return val
    
        def set_callback(self, f):
            self.cb = f
    
        def set_will(self, will_topic, will_message, will_qos=0, will_retain=0):
            if will_topic:
                self.__will_topic = will_topic.encode('utf8')
            self.__will_message = will_message
            self.__will_qos = will_qos
            self.__will_retain = will_retain
    
        def connect(self, clean_session=True, ssl=False, certfile=None, keyfile=None, ca_certs=None):
            try:
                self.poll.unregister(self.sock)
            except:
                pass
            self.sock = socket.socket()
    
            if ssl:
                import ssl
                self.sock = ssl.wrap_socket(self.sock, certfile=certfile, keyfile=keyfile, ca_certs=ca_certs, cert_reqs=ssl.CERT_REQUIRED)
    
            self.sock.connect(self.addr)
            self.poll.register(self.sock, select.POLLIN)
    
            pkt_len = (12 + len(self.client_id) + # 10 + 2 + len(client_id)
                        (2 + len(self.__user) if self.__user else 0) +
                        (2 + len(self.__password) if self.__password else 0))
    
            flags = (0x80 if self.__user else 0x00) | (0x40 if self.__password else 0x00) | (0x02 if clean_session else 0x00)
    
            if self.__will_message:
                flags |= (self.__will_retain << 3 | self.__will_qos << 1 | 1) << 2
                pkt_len += 4 + len(self.__will_topic) + len(self.__will_message)
    
            pkt = bytearray([0x10]) # connect
            pkt.extend(self.__encode_varlen_length(pkt_len)) # len of the remaining
            pkt.extend(b'\x00\x04MQTT\x04') # len of "MQTT" (16 bits), protocol name, and protocol version
            pkt.append(flags)
            pkt.extend(b'\x00\x00') # disable keepalive
            pkt.extend(self.__pascal_string(self.client_id))
            if self.__will_message:
                pkt.extend(self.__pascal_string(self.__will_topic))
                pkt.extend(self.__pascal_string(self.__will_message))
            if self.__user:
                pkt.extend(self.__pascal_string(self.__user))
            if self.__password:
                pkt.extend(self.__pascal_string(self.__password))
    
            self.sock.send(pkt)
            resp = self.sock.recv(4)
            assert resp[0] == 0x20 and resp[1] == 0x02
            if resp[3] != 0:
                raise MQTTException(resp[3])
            return resp[2] & 1
    
        def disconnect(self):
            self.sock.send(b"\xe0\0")
            self.sock.close()
    
        def ping(self):
            self.sock.send(b"\xc0\0")
    
        def publish(self, topic, msg, retain=False, qos=0, dup=0):
            topic = topic.encode('utf8')
            hdr = 0x30 | (dup << 3) | (qos << 1) | retain
            pkt_len = (2 + len(topic) +
                        (2 if qos else 0) +
                        (len(msg)))
    
            pkt = bytearray()
            pkt.append(hdr)
            pkt.extend(self.__encode_varlen_length(pkt_len)) # len of the remaining
            pkt.extend(self.__pascal_string(topic))
            if qos:
                self.pid += 1 #todo: I don't think this is the way to deal with the packet id
                pkt.extend(self.__encode_16(self.pid))
    
            self.sock.send(pkt)
            self.sock.send(msg)
    
            #todo: check next part of the code
            if qos == 1:
                while 1:
                    rcv_pid = self.recv_pubconf(0)
                    if pid == rcv_pid:
                        return
            elif qos == 2:
                assert 0
    
        def recv_pubconf(self, t):
            headers = [0x40, 0x50, 0x62, 0x70]
            header = headers[t]
            while 1:
                op = self.wait_msg()
                if op == header:
                    sz = self.sock.recv(1)
                    assert sz == b"\x02"
                    return
    
        def subscribe(self, topic, qos=0):
            assert self.cb is not None, "Subscribe callback is not set"
    
            topic = topic.encode('utf8')
            pkt_len = 2 + 2 + len(topic) + 1 # packet identifier + len of topic (16 bits) + topic len + QOS
    
            self.pid += 1
            pkt = bytearray([0x82])
            pkt.extend(self.__encode_varlen_length(pkt_len)) # len of the remaining
            pkt.extend(self.__encode_16(self.pid))
            pkt.extend(self.__pascal_string(topic))
            pkt.append(qos)
    
            self.sock.send(pkt)
            resp = self.sock.recv(5)
            #print(resp)
            assert resp[0] == 0x90
            assert resp[2] == pkt[2] and resp[3] == pkt[3]
            if resp[4] == 0x80:
                raise MQTTException(resp[4])
    
        # Wait for a single incoming MQTT message and process it.
        # Subscribed messages are delivered to a callback previously
        # set by .set_callback() method. Other (internal) MQTT
        # messages processed internally.
        def wait_msg(self):
            res = self.sock.recv(1)
            self.sock.setblocking(True)
            if res is None or res == b"":
                return None
            #if res == b"":
            #    raise OSError(-1)
            if res == b"\xd0":  # PINGRESP
                sz = self.sock.recv(1)[0]
                assert sz == 0
                return None
            op = res[0]
            if op & 0xf0 != 0x30:
                return op
            sz = self.__recv_varlen_length()
            topic_len = self.sock.recv(2)
            topic_len = (topic_len[0] << 8) | topic_len[1]
            topic = self.sock.recv(topic_len)
            sz -= topic_len + 2
            if op & 6:
                pid = self.sock.recv(2)
                pid = pid[0] << 8 | pid[1]
                sz -= 2
            msg = self.sock.recv(sz)
            self.cb(topic, msg)
            if op & 6 == 2:
                pkt = bytearray(b"\x40\x02\0\0")
                struct.pack_into("!H", pkt, 2, pid)
                self.sock.send(pkt)
            elif op & 6 == 4:
                assert 0
    
        # Checks whether a pending message from server is available.
        # If not, returns immediately with None. Otherwise, does
        # the same processing as wait_msg.
        def check_msg(self):
            self.sock.setblocking(False)
            return self.wait_msg()
    
    
    

  • Pybytes Beta

    @noobiemcfoob Could you also share demo.py with us.

    WiFi logging from REPL seems ok to me. So it should be something else.

    Are you using a guest wifi in which you should also provide username, password to logon?


  • Pybytes Beta

    @gertjanvanhethof, sure. Here's the REPL output following reset showing the WiPy connecting to my network (Cisco02775). I was able to verify the connection by pinging the WiPy on the network from a different device.

    rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0x00
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:QIO, clock div:2
    load:0x3fff9010,len:8
    load:0x3fff9018,len:268
    ho 0 tail 12 room 4
    load:0x40078000,len:2656
    load:0x4009f000,len:2040
    entry 0x4009f12c
    tcpip_task_hdlxxx : 3ffd4530, prio:18,stack:2048
    I (1698) wifi: frc2_timer_task_hdl:3ffd7b48, prio:22, stack:2048
    I (1703) wifi: pp_task_hdl : 3ffda3f8, prio:23, stack:8192
    I (1703) wifi: sleep disable
    I (2678) wifi: mode : softAP (24:0a:c4:00:a4:f7)
    dhcp server start:(ip: 192.168.4.1, mask: 255.255.255.0, gw: 192.168.4.1)
    I (2758) wifi: sleep enable
    I (2759) wifi: type: 1
    I (2759) wifi: mode : sta (24:0a:c4:00:a4:f6)
    MicroPython v1.8.6-422-g516b861 on 2017-02-07; WiPy with ESP32
    Type "help()" for more information.
    >>> I (6561) wifi: n:6 0, o:6 0, ap:255 255, sta:6 0, prof:6
    I (7535) wifi: state: init -> auth (b0)
    I (7537) wifi: state: auth -> assoc (0)
    I (7541) wifi: state: assoc -> run (10)
    I (7559) wifi: connected with Cisco02775, channel 6
    I (17541) wifi: pm start, type:1
    
    
    >>> from demo import *
    >>> run()
    Error connecting to the server: [Errno 113] EHOSTUNREACH
    Error connecting to the server: -32512
    Error connecting to the server: -32512
    Error connecting to the server: -32512
    Error connecting to the server: -32512
    Error connecting to the server: -32512
    Error connecting to the server: -32512
    Error connecting to the server: -16912
    Error connecting to the server: -10368
    Error connecting to the server: -10368
    Error connecting to the server: -10368
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Error connecting to the server: 23
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "demo.py", line 38, in run
    KeyboardInterrupt: 
    >>> 
    

    Is there anything else I could provide as a clue?



  • This post is deleted!

  • Pybytes Beta

    Can you give us more details. For example, what is the output in you REPL window after a soft reboot?


Log in to reply
 

Looks like your connection to Pycom Forum was lost, please wait while we try to reconnect.