esp32-net6-serial

Cómo conectar un ESP32 con NET6 por puerto serie

Estrenamos una serie de entradas destinadas a ver las distintas formas de conectar un ESP32 con un ordenador a través de una aplicación hecha en NET6, escrita en C#.

Recordemos que NET6 es multiplataforma y, por tanto, está disponible tanto en ordenadores con Windows, Android, Linux o Mac, asi como en arquitecturas x86/x64 y ARM7 o superior.

Esto significa que podemos ejecutar el mismo programa, por ejemplo, tanto en nuestro ordenador de sobre mesa con Windows o Linux, como en nuestro móvil Android, o en nuestra Raspberry Pi. Todo ello sin necesidad de realizar ningún cambio en el código.

Y comenzamos la serie viendo una de las formas más sencillas de comunicación, que usar un puerto de serie (o UART).

Código ESP32

Para esta serie de entradas voy a usar un dispositivo M5 Stick C, que tiene incorporada una pantalla y un acelerómetro, porque me resulta muy útil para desarrollar el contenido. Pero cualquier dispositivo similar a un Arduino con Wifi, como cualquier modelo de la familia ESP32, nos va a servir.

En el repo del Github os dejo los ejemplos completos, con el código del ESP32 y el de NET. Tenéis en enlace al final de la entrada. Aquí vamos a comentar únicamente las partes relevantes. En el repo tenéis cuatro ejemplos:

  • 00_Timer
  • 01_Button
  • 02_Accelerometer
  • 03_Receive

En los tres primeros ejemplos el ESP32 envía un dato a la aplicación en NET6. El primer ejemplo es el más sencillo, y simplemente enviamos las ordenes con una temporización. En el segundo, cuando pulsamos un botón. En el tercero, mandamos la orden en función de que el dispositivo se encuentre vertical o tumbado, empleando el acelerómetro del M5 Stick C.

Si miramos, por ejemplo, el código del caso del acelerómetro, la parte del envió la realizamos en la función Update(),

void Update()
{
  if(isOn == false && GetIsTumbado() == false)
  {
    isOn = true;
    Serial.println("A");
  }
  else if(isOn == true && GetIsTumbado() == true)
  {
    isOn = false;
    Serial.println("B");
  }
}

Vemos que simplemente usamos Serial.println(…) para enviar los datos a la aplicación de NET6, donde básicamente estoy usando el acelerómetro para detectar cuando el dispositivo está tumbado o de pie.

Así de sencillo. Los otros dos ejemplos tienen una función de Update(…) similar, con pequeñas variaciones en función del caso particular. Pero la parte de comunicación serial es, básicamente, igual de sencilla.

En cuarto ejemplo, ‘Receive’, el ESP32 recibe un dato enviado desde la aplicación. En este caso la función ‘Update()’ seria la siguiente,

void Update()
{
  if (Serial.available())
  {
    auto content = Serial.readStringUntil(‘\n’);
    if(content == "A") isOn = true;
    if(content == "B") isOn = false;

    Render();
  }
}

Donde simplemente comprobamos si existe un dato pendiente de recibir, usando el separador de nueva línea ‘\n’. A continuación leemos el contenido, y realizaríamos las acciones oportunas. En el ejemplo, simplemente cambiamos la pantalla a rojo o verde, en función de valor recibido.

Código NET6

Por otro lado, pasando al lado NET6, creamos una simple aplicación de consola. A continuación, añadimos el ensamblado System.IO.Port.

Para mantener un mínimo de limpieza, encapsulamos la lógica del programa asociada al puerto de serie en un objeto independiente. Os dejo una estructura básica en el fichero ArduinoPort.cs. Podéis reusarlo en vuestro proyecto, o modificarlo según vuestras necesidades.

Con esto, el código para el envío desde NET6 al ESP32 seria el siguiente,

ArduinoPort arduinoPort = new ArduinoPort();
arduinoPort.DataArrived += ArduinoPort_DataArrived;

// ejemplo USB port en Windows
arduinoPort.Open("COM4", 115200);

// ejemplo USB port en Linux
//arduinoPort.Open("/dev/ttyUSB0", 115200);

Console.ReadLine();

void ArduinoPort_DataArrived(object? sender, EventArgs? e)
{
  var lastRecieved = arduinoPort.LastRecieved;
  Console.WriteLine(lastRecieved);
}

Compilamos el código y lo ejecutamos, bien sea en un ordenador con Windows, una Raspberry Pi o cualquier otras plataformas disponibles. Únicamente debemos tener en cuenta que debemos sustituir el puerto COMx o ttyUSBx, por el nombre el nombre del puerto en nuestro dispositivo.

Ahora, con el dispositivo conectado por USB, al tumbar el dispositivo, vemos que en la aplicación de consola se muestran las ‘A’ y ‘B’ recibidas. Con esto, haríamos las acciones oportunas. De igual forma que podríamos mandar ‘A’ y ‘B’ o cualquier otra información, como ya hemos visto en las numerosas entradas sobre puerto serie del blog.

En el caso de querer que sea la aplicación NET6 la que envíe información al ESP32, que correspondería con el ejemplo 03_Receive.ino, podemos usar la función ‘arduinoPort.Write(…);

Por ejemplo, con el siguiente código enviaríamos de forma alterna ‘A’ y ‘B’ cada dos segundos, por lo que la pantalla conectada al ESP32 cambiaría de verde a roja.

var isOn = false;
var timer = Observable.Interval(TimeSpan.FromSeconds(2))
  .Subscribe(async _ =>
  {
    var message = isOn ? "A" : "B";
    isOn = !isOn;
    
    arduinoPort.Write(message);
    Console.WriteLine(message);
  });

Así de sencillo podríamos comunicar un ESP32 con una aplicación de NET6 escrita en C#. En la próxima entrada de la serie pasaremos a comunicación inalámbrica a traves de WiFi, viendo como emplear peticiones HTTP.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full