PPP over Serial (PPPoS) support for MicroPython on ESP32

Introduction

At PPP over Serial (PPPoS) support for SIM800 within ESP-IDF for ESP32, we looked at PPPoS support within the Espressif SDK for ESP32 (ESP-IDF). Here, we are looking for corresponding MicroPython support.

It looks like appropriate support from Genuine MicroPython has been here just hidden in plain sight – since MicroPython 1.10 already.

To be safe, we might want to compare that AT command sequence to initialize a PPPoS connection with the Loboris MicroPython implementation at libGSM.c. Hint: While Boris uses some additional commands, this looks good already!

We have tried to implemented this for @sarusso’s SIM800 driver module, however it is still untested (WIP).

Hi,

Thank to what Andread did, I have been able to send MQTT commands using PPP over UART. In my case I used a BGS2T modem from Cinterion to get communication. On the other side I had an ESP32 Wrover kit. I hope this can help or add value to the post above.

# File main.py
"""
PPP over Serial (PPPoS) support for MicroPython on ESP32. Also, send AT commands by MQTT.
"""
from machine import Pin
from machine import UART
import time
import network
import umqtt.robust as mqtt


"""
Pin config.
"""
RED_PIN = 0
GREEN_PIN = 2
BLUE_PIN = 4
TX_UART_PIN = 1
RX_UART_PIN = 3
BAUDRATE = 115200
"""
MQTT
"""
MQTT_SERVER = "35.157.18.117"	#http://www.hivemq.com/demos/websocket-client/
MQTT_PORT = 1883
ID_CLIENT = "pepino_yeah"
TOPIC_SUB = "cubata"
TOPIC_PUB = "pepino"
"""
Global
"""
debug = None
esp_client = None
close_session = False


def sub_cb(topic, msg):
    """
    Callback function that will run whenever a message is published on a topic the ESP is subscribed to.
    """
    global close_session
    debug.print("(" + ",".join((topic.decode("utf-8"), msg.decode("utf-8"))) + ")")
    if msg.decode("utf-8") == "close":
        esp_client.publish(TOPIC_PUB, "### Closing pepino session... ###")
        close_session = True
    else:
        esp_client.publish(TOPIC_PUB, "Echo: " + msg.decode("utf-8"))


def connect_subscribe():
    """
    Connect to MQTT broker and subscribe to a topic.
    :return: MQTT client object.
    """
    client = mqtt.MQTTClient(ID_CLIENT, MQTT_SERVER, MQTT_PORT)
    client.set_callback(sub_cb)
    client.connect()
    client.subscribe(TOPIC_SUB)
    debug.print('Connected to \'%s\' MQTT broker, subscribed to \'%s\' topic' % (MQTT_SERVER, TOPIC_SUB))
    client.publish(TOPIC_PUB, "### Pepino session started ###")
    return client


def restart_and_reconnect():
    """
    If not possible to connect to MQTT broker, retry.
    """
    debug.print('Failed to connect to MQTT broker. Reconnecting...')
    time.sleep(10)


class Esp32:
    def __init__(self):
        """
        Initialize ESP32 machine.
        """
        self.data = None
        self.red_led = Pin(RED_PIN, Pin.OUT)
        self.green_led = Pin(GREEN_PIN, Pin.OUT)
        self.blue_led = Pin(BLUE_PIN, Pin.OUT)

        self.uart = UART(1, BAUDRATE, tx=TX_UART_PIN, rx=RX_UART_PIN)
        #self.uart = UART(1, BAUDRATE)
        self.uart.read()    # Clean buffer

    def send_at(self, at_cmd, wait_time=0, debug_mode=True):
        """
        Send AT command. Waiting time for response is configurable (seconds).
        """
        self.uart.read()  # Clean buffer
        debug.print(at_cmd)
        self.uart.write(at_cmd + "\r\n")
        if debug_mode:
            time.sleep(wait_time)
            self.data = self.uart.read()
            if self.data is None:
                debug.print("...No response")
            else:
                debug.print(self.data.decode("utf-8"))
        time.sleep(1)


class Debug:
    def __init__(self, filename):
        """
        Delete previous output file and create a new one.
        """
        self.output = open(filename, "w")

    def print(self, text):
        #print(text)
        self.output.write(text + "\n")

    def close(self):
        self.output.close()


if __name__ == '__main__':
    # Create a new debug class
    debug = Debug("output.txt")
    debug.print("START")

    # Create and initialize ESP32 device class.
    debug.print("Create and initialize ESP32 device class")
    device = Esp32()

    try:
        device.green_led.on()
        time.sleep(1)

        # Send AT command list.
        device.send_at("AT", 1)
        device.send_at("ATI", 1)
        device.send_at("AT+CPIN?", 1)
        device.send_at("AT+CREG?", 1)
        device.send_at("AT+COPS?", 1)
        device.send_at("AT+CGDCONT=1,\"IP\",\"movistar.es\"", 1)
        device.send_at("AT+CGACT=1,1", 5)
        device.send_at("AT+CGDATA=\"PPP\",1", debug_mode=False)

        time.sleep(5)

        # Start PPPoS protocol
        debug.print("Start PPPoS protocol")
        ppp = network.PPP(device.uart)
        ppp.active(True)
        ppp.connect()

        time.sleep(15)

        debug.print("IP config: (" + ",".join(ppp.ifconfig()) + ")")

        if ppp.isconnected():
            device.blue_led.on()

            esp_client = connect_subscribe()

            while True:
                esp_client.check_msg()
                if close_session:
                    esp_client.disconnect()
                    time.sleep(5)
                    break

        debug.print("END")

        debug.close()

        device.green_led.off()
        device.blue_led.off()
    except Exception as e:
        device.green_led.off()
        device.blue_led.off()
        device.red_led.on()
        debug.print(str(e))
        debug.close()
2 Likes

Dear Miguel,

Wow - indeed that is very sweet! Do you think you would be able to craft a corresponding patch for SIM800L.py, based on my Add PPP over Serial (PPPoS) support by amotl · Pull Request #5 · pythings/Drivers · GitHub? I think it would be a great benefit for the community.

With kind regards,
Andreas.


  1. P.S.: Thank you for telling us about those kinds of devices. [2]

    ↩︎
  2. Wow, what a history. Siemens AG Wireless Modules » Cinterion Wireless Modules GmbH (CWM) [2008] » Gemalto [2010] » Thales Group [2019]. [3]

    ↩︎
  3. Historic and contemporary products of the same line

    ↩︎
1 Like

Hi Andreas,

I am glad of you like it. I did it just for testing and see the viability with a project.

Regarding to craft a patch for SIM800.py, I would really like to get on with it, but I have no SIM800 modules which with to test. Maybe in the future when I have more time, I can get one and play with him and give some support to the community.

Regards,
Miguel

1 Like

Oh I see. So the AT commands outlined within your program are specific to the Cinterion BGS2T modem? The other parts of the code look pretty generic, no?

So the AT commands outlined within your program are specific to the Cinterion BGS2T modem?

I had to search about this because I did not know if these AT commands were specific (as I said, I do not have SIM800 samples).

I have found an AT command manual of SIM800 here: https://www.elecrow.com/wiki/images/2/20/SIM800_Series_AT_Command_Manual_V1.09.pdf

The AT commands from my code are not specific to the Cinterion BGS2T modem. They appear for SIM800 as well, so they seem to be compatible. It would have to be tested.

The other parts of the code look pretty generic, no?

Yes.

1 Like