almacenamiento-guardar-configuracion-flash-nanoframework

Guardar configuración en la flash con nanoFramework

  • 5 min

El almacenamiento persistente es guardar datos aunque el microcontrolador se reinicie.

Hasta ahora, nuestro código vivía en la memoria RAM. La RAM es rápida, pero volátil: si quitas la energía, los datos desaparecen.

Un dispositivo puede necesitar guardar datos de forma permanente:

  • Credenciales Wi-Fi (SSID/Pass).
  • Tokens de autenticación (API Keys).
  • Preferencias de usuario (Umbrales de alarma, colores de LEDs).

En Arduino solíamos usar la librería EEPROM o Preferences. En nanoFramework, subimos de nivel y utilizamos el espacio de nombres System.IO.

Vamos a usar una API familiar de archivos, aplicada a la memoria flash interna del ESP32.

Para este tutorial necesitas instalar el paquete NuGet: nanoFramework.System.IO.FileSystem

El sistema de archivos interno

El ESP32 tiene una memoria Flash (donde se guarda tu código). nanoFramework reserva una partición de esa memoria para que puedas usarla como si fuera un “disco duro” muy pequeño.

Dependiendo de cómo esté configurado tu firmware (aunque es el estándar), esta unidad interna suele montarse en la unidad I:\ (de Internal).

Esto significa que podemos crear, leer y escribir archivos en I:\config.txt usando clases estándar de .NET.

Guardar texto plano

Vamos a empezar por lo básico: guardar un mensaje simple.

using System;
using System.Diagnostics;
using System.IO; // <--- Espacio de nombres clave

public static void EscribirArchivo()
{
    // Ruta en el almacenamiento interno
    string ruta = "I:\\nota.txt";

    try
    {
        // Verificar si existe
        if (File.Exists(ruta))
        {
            Debug.WriteLine("El archivo ya existe. Borrando...");
            File.Delete(ruta);
        }

        // Escribir texto
        // WriteAllText abre, escribe y cierra el archivo automáticamente
        File.WriteAllText(ruta, "Hola desde el pasado (antes del reinicio)");
        
        Debug.WriteLine("Archivo guardado correctamente.");
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"Error escribiendo archivo: {ex.Message}");
    }
}

public static void LeerArchivo()
{
    string ruta = "I:\\nota.txt";

    if (File.Exists(ruta))
    {
        string contenido = File.ReadAllText(ruta);
        Debug.WriteLine($"Leído del disco: {contenido}");
    }
    else
    {
        Debug.WriteLine("El archivo no existe.");
    }
}
Copied!

Si ejecutas EscribirArchivo(), reinicias tu ESP32 (cortando corriente) y luego ejecutas LeerArchivo(), verás que el mensaje sigue ahí. Justo lo que queríamos.

Guardar configuración JSON

Para una configuración con varios campos, podemos combinar System.IO con nanoFramework.Json. ¿Recuerdas la lección de JSON? Vamos a combinar System.IO con nanoFramework.Json para crear un sistema de configuración profesional.

Definir la clase de configuración

public class AppConfig
{
    public string Ssid { get; set; } = "MiWifi";
    public string Password { get; set; } = "1234";
    public int IntervaloLectura { get; set; } = 60; // Segundos
    public string DeviceName { get; set; } = "Sensor_01";
}
Copied!

Crear el gestor de configuración

Vamos a crear una clase estática que se encargue de cargar y guardar esta configuración.

using System.IO;
using nanoFramework.Json;

public static class ConfigurationManager
{
    private const string RutaConfig = "I:\\appsettings.json";

    public static void Guardar(AppConfig config)
    {
        // 1. Serializar el objeto a texto JSON
        string json = JsonConvert.SerializeObject(config);

        // 2. Guardar en disco
        File.WriteAllText(RutaConfig, json);
    }

    public static AppConfig Cargar()
    {
        // Si no existe el archivo, devolvemos una config por defecto
        if (!File.Exists(RutaConfig))
        {
            return new AppConfig();
        }

        // 1. Leer del disco
        string json = File.ReadAllText(RutaConfig);

        // 2. Deserializar
        try 
        {
            return (AppConfig)JsonConvert.DeserializeObject(json, typeof(AppConfig));
        }
        catch
        {
            // Si el archivo está corrupto, devolvemos default
            return new AppConfig();
        }
    }
}
Copied!

Usarlo desde Main

Ahora tu programa principal es mucho más limpio y robusto.

public static void Main()
{
    // Cargar configuración al inicio
    AppConfig miConfig = ConfigurationManager.Cargar();

    Debug.WriteLine($"Iniciando dispositivo: {miConfig.DeviceName}");
    Debug.WriteLine($"Conectando a Wi-Fi: {miConfig.Ssid}...");

    // ... lógica de conexión ...

    // Supongamos que recibimos una orden por MQTT para cambiar el intervalo
    // ...
    miConfig.IntervaloLectura = 120;
    
    // Guardamos para que el cambio persista tras reiniciar
    ConfigurationManager.Guardar(miConfig);
    Debug.WriteLine("Configuración actualizada guardada.");

    Thread.Sleep(Timeout.Infinite);
}
Copied!

La memoria flash se desgasta

Es muy importante entender el hardware que hay debajo. La memoria Flash de un ESP32 tiene un número limitado de ciclos de escritura (típicamente entre 10,000 y 100,000).

  • Lectura: Infinita. Puedes leer Cargar() todas las veces que quieras.
  • Escritura: Limitada.

Mala práctica: Guardar la configuración dentro de un bucle cada segundo. Destruirás la memoria Flash de tu chip en pocas semanas. Buena práctica: Guardar solo cuando algo cambia (ej. el usuario cambia una configuración desde la web) o cada intervalos muy largos (ej. contadores acumulados una vez cada hora).

No guardes contraseñas o tokens como JSON en texto plano sin analizar el riesgo. El sistema de archivos aporta persistencia, no cifrado.

Tarjetas SD para más capacidad

¿Y si queremos guardar un Log de Datos (Datalogger)? Si queremos guardar la temperatura cada 10 segundos durante un año, la memoria interna de 4MB se llenará enseguida.

Para eso usamos tarjetas SD. nanoFramework soporta tarjetas SD conectadas por SPI o SDMMC.

El código es casi idéntico, solo cambia la unidad. Al montar la tarjeta SD, normalmente aparecerá como D:\ (o la letra que asigne el sistema).

// Escribir en la tarjeta SD
File.AppendAllText("D:\\datalog.csv", $"{DateTime.UtcNow},24.5\r\n");
Copied!

Nota: Para usar la SD necesitas código de inicialización adicional para montar la unidad (StorageEventManager), pero la lógica de lectura/escritura es la misma System.IO.