main/config.c

Fri, 28 Jun 2024 15:33:24 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 28 Jun 2024 15:33:24 +0200
branch
idf 5.1
changeset 137
e0f50087c909
parent 129
31f9d3e4a85f
permissions
-rw-r--r--

Fixed changing runtime datarecord size during switching between IDF 4.2 and 5.1. Fixed wiping the /spiffs filesystem. The directory listing from the SD card doesn't overwrite parts of the screen anymore. Solved the slow speed issue with the SD card. Try to force the SD card to operate at 20 MHz. More project settings changed to improve performance and memory usage.

/**
 * @file config.c
 * @brief BrewBoard configuration files.
 */

#include "config.h"

static const char *TAG = "config";

my_config_t		config;
my_equipment_hdr_t	equipment_hdr;
my_equipment_t		equipment;
my_wifiStation_t	wifiStation;
my_runtime_t		runtime;
my_recipe_hdr_t		recipe_hdr;
my_recipe_t		recipe;


void write_config() {
    uint8_t *dst = (uint8_t *)&config;
    FILE *f = fopen("/spiffs/etc/config.conf", "w+");
	      
    if (f == NULL) {
	ESP_LOGE(TAG, "write /spiffs/etc/config.conf failed");
	return;
    }

    size_t bytes = fwrite(dst, 1, sizeof(config), f);
    fclose(f);
    if (bytes != sizeof(config)) {
	ESP_LOGE(TAG, "/spiffs/etc/config.conf written %d/%d bytes", bytes, sizeof(config));
    }
}



void read_config() {
    uint8_t	*dst;
    uint8_t	mac_addr[8] = {0};
    FILE	*f = fopen("/spiffs/etc/config.conf", "r");

    if (f == NULL) {
	// No configuration yet, create it.
	esp_efuse_mac_get_default(mac_addr);
	config.Version = 1;
	config.Unit = 'C';
	config.BoilTemperature = 99.0;
	config.AskAdd = true;
	config.AskRemove = true;
	config.AskIodine = true;
	config.IodineTime = 30;
	config.EquipmentRec = 1;
	sprintf(config.hostname, "brewboard-%02x%02x%02x", mac_addr[3], mac_addr[4], mac_addr[5]);
	config.xap_ssid[0] = '\0';
	config.xap_pwd[0] = '\0';
	config.xap_channel = 0;
	config.xap_ssid_hidden = 0;
	config.xap_bandwidth = 0;
	config.ts_xleft = 0;
	config.ts_xright = 3600;
	config.ts_ytop = 3600;
	config.ts_ybottom = 0;
	config.RecipeRec = 1;
	sprintf(config.uuid, "c0ffeeee-dead-beef-cafe-%02x%02x%02x%02x%02x%02x", 
			mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); 
	write_config();
    } else {
	dst = (uint8_t*)&config;
	fread(dst, 1, sizeof(config), f);
	fclose(f);
    }
}



void append_equipment()
{
    uint8_t *dst = (uint8_t *)&equipment;
    FILE *f = fopen("/spiffs/etc/equipments.conf", "a");
	      
    if (f == NULL) {
	ESP_LOGE(TAG, "/spiffs/etc/equipments.conf append failed");
	return;
    }

    size_t bytes = fwrite(dst, 1, equipment_hdr.recsize, f);
    fclose(f);
    ESP_LOGI(TAG, "/spiffs/etc/equipments.conf appended %d bytes", bytes);
}



void read_equipment(int RecNo)
{
    size_t	bytes;
    uint8_t	*dst;
    FILE	*f = fopen("/spiffs/etc/equipments.conf", "r");

    if (f == NULL) {
	// No configuration yet, create it.
	dst = (uint8_t*)&equipment_hdr;
        memset(dst, 0, sizeof(equipment_hdr));
        equipment_hdr.version = EQUIPMENT_VERSION;
        equipment_hdr.hdrsize = sizeof(equipment_hdr);
        equipment_hdr.recsize = sizeof(equipment);
        f = fopen("/spiffs/etc/equipments.conf", "w");
        bytes = fwrite(dst, 1, sizeof(equipment_hdr), f);
        if (bytes != sizeof(equipment_hdr)) {
            ESP_LOGE(TAG, "/spiffs/etc/equipment.conf write header, %d/%d bytes", bytes, sizeof(equipment_hdr));
        }
	dst = (uint8_t*)&equipment;
        memset(dst, 0, sizeof(equipment));
	equipment.MLT_watt = 2000;
	equipment.HLT_watt = 2000;
	sprintf(equipment.Name, "default");
	equipment.BoilPower = 80;
	equipment.MashPower = 100;
	equipment.PumpCycle = 8;
	equipment.PumpRest = 2;
	equipment.PumpPreMash = true;
	equipment.PumpOnMash = true;
	equipment.PumpMashOut = true;
	equipment.PumpOnBoil = false;
	equipment.PumpMaxTemp = 80;
	equipment.PIDPipe = true;
	equipment.SSR2 = 0;
	equipment.TempHLT = 85.0;
	equipment.PID_kP = 200.0;
	equipment.PID_kI = 2.0;
	equipment.PID_kD = 1.5;
	equipment.SampleTime = 3000;
	equipment.Hendi = false;
	equipment.RampPower = 100;
	equipment.Max_watt = 2750;
	bytes = fwrite(dst, 1, sizeof(equipment), f);
	fclose(f);
    } else {
	/*
	 * Try to read the new header
	 */
	dst = (uint8_t*)&equipment_hdr;
        fseek(f, 0, SEEK_SET);
        bytes = fread(dst, 1, sizeof(equipment_hdr), f);
        if (bytes != sizeof(equipment_hdr)) {
            ESP_LOGE(TAG, "/spiffs/etc/equipments.conf read header, %d/%d bytes", bytes, sizeof(equipment_hdr));
            fclose(f);
            return;
        }
#if 1
	if (equipment_hdr.version < EQUIPMENT_VERSION) {
	    uint32_t	oldsize = equipment_hdr.recsize;
	    FILE	*nf = fopen("/spiffs/etc/equipments.new", "w");

            ESP_LOGW(TAG, "/spiffs/etc/equipments.conf version %u, new %d", (unsigned)equipment_hdr.version, EQUIPMENT_VERSION);
	    dst = (uint8_t*)&equipment_hdr;
            memset(dst, 0, sizeof(equipment_hdr));
	    // Update the header with new sizes
            equipment_hdr.version = EQUIPMENT_VERSION;
            equipment_hdr.hdrsize = sizeof(equipment_hdr);
            equipment_hdr.recsize = sizeof(equipment);
            bytes = fwrite(dst, 1, sizeof(equipment_hdr), nf);

            dst = (uint8_t*)&equipment;
            while ((bytes = fread(dst, 1, oldsize, f))) {
                // Upgrade data here
		equipment.Hendi = false;
		equipment.RampPower = equipment.BoilPower;
		equipment.Max_watt = 3000;
                bytes = fwrite(dst, 1, sizeof(equipment), nf);
                if (bytes != sizeof(equipment)) {
                    ESP_LOGE(TAG, "/spiffs/etc/equipments.new write data, %u/%d bytes", (unsigned)bytes, sizeof(equipment));
                }
            }
            fclose(nf);
            fclose(f);
            rename("/spiffs/etc/equipments.conf", "/spiffs/etc/equipments.old");
            rename("/spiffs/etc/equipments.new", "/spiffs/etc/equipments.conf");
            unlink("/spiffs/etc/equipments.old");
	    f = fopen("/spiffs/etc/equipments.conf", "r");
	    dst = (uint8_t*)&equipment_hdr;
	    fread(dst, 1, sizeof(equipment_hdr), f);
	}
#endif
	dst = (uint8_t*)&equipment;
	fseek(f, (RecNo - 1) * equipment_hdr.recsize + equipment_hdr.hdrsize, SEEK_SET);
	bytes = fread(dst, 1, equipment_hdr.recsize, f);
	fclose(f);
	if (bytes != equipment_hdr.recsize) {
	    ESP_LOGE(TAG, "/spiffs/etc/equipments.conf read record %d, %u/%u bytes", RecNo, (unsigned)bytes, (unsigned)equipment_hdr.recsize);
	} else {
	    ESP_LOGI(TAG, "/spiffs/etc/equipments.conf read %d bytes, record %d: %s", bytes, RecNo, equipment.Name);
	}
    }
}



void write_equipment(int RecNo)
{
    uint8_t     *dst = (uint8_t *)&equipment;
    FILE        *f;

    f = fopen("/spiffs/etc/equipments.conf", "r+");
    if (f == NULL) {
	ESP_LOGE(TAG, "/spiffs/etc/equipments.conf write failed");
	return;
    }
    fseek(f, (RecNo - 1) * equipment_hdr.recsize + equipment_hdr.hdrsize, SEEK_SET);
    size_t bytes = fwrite(dst, 1, equipment_hdr.recsize, f);
    fclose(f);
    if (bytes != equipment_hdr.recsize)
	ESP_LOGE(TAG, "/spiffs/etc/equipments.conf write record %d, %u/%u bytes", RecNo, (unsigned)bytes, (unsigned)equipment_hdr.recsize);
    else
	ESP_LOGI(TAG, "/spiffs/etc/equipments.conf update record %d, %u bytes", RecNo, (unsigned)bytes);
}



void delete_equipment(int RecNo)
{
    int		RecRead = 1, RecWrite = 1;
    FILE	*n, *o;
    uint8_t	*dst;
    size_t	bytes;

    n = fopen("/spiffs/etc/equipments.new", "a");
    if (n == NULL) {
	ESP_LOGE(TAG, "/spiffs/etc/equipments.new create error");
	return;
    }
    o = fopen("/spiffs/etc/equipments.conf", "r");
    if (o == NULL) {
	ESP_LOGE(TAG, "/spiffs/etc/equipments.conf open error");
	fclose(n);
	unlink("/spiffs/etc/equipments.new");
	return;
    }

    dst = (uint8_t*)&equipment_hdr;
    fread(dst, 1, equipment_hdr.hdrsize, o);
    fwrite(dst, 1, equipment_hdr.hdrsize, n);

    dst = (uint8_t*)&equipment;
    while (true) {
	bytes = fread(dst, 1, equipment_hdr.recsize, o);
	if (bytes == 0)
	    break;

	if (RecRead != RecNo) {
	    // Record to copy
	    if ((config.EquipmentRec == RecRead) && (config.EquipmentRec != RecWrite)) {
		// We need to change the default record.
		config.EquipmentRec = RecWrite;
		write_config();
	    }
	    fwrite(dst, 1, equipment_hdr.recsize, n);
	    RecWrite++;
	}
	RecRead++;
    }
    fclose(o);
    fclose(n);

    rename("/spiffs/etc/equipments.conf", "/spiffs/etc/equipments.old");
    rename("/spiffs/etc/equipments.new", "/spiffs/etc/equipments.conf");
    unlink("/spiffs/etc/equipments.old");
    ESP_LOGI(TAG, "Deleted equipment %d, %d left", RecNo, RecWrite - 1);
}



int add_station(uint8_t *SSID, uint8_t *Password)
{
    FILE	*f;
    uint8_t     *dst = (uint8_t *)&wifiStation;

    if (read_station(SSID) >= 0) {
	ESP_LOGE(TAG, "add_station %s already excists", SSID);
	return -1;
    }

    f = fopen("/spiffs/etc/stations.conf", "a+");
    if (f == NULL) {
	ESP_LOGE(TAG, "write /spiffs/etc/stations.conf failed");
	return -1;
    }
    memset(dst, 0, sizeof(wifiStation));
    sprintf(wifiStation.SSID, "%s", (char *)SSID);
    sprintf(wifiStation.Password, "%s", (char *)Password);
    wifiStation.hide = false;
    fwrite(dst, 1, sizeof(wifiStation), f);
    fclose(f);

    ESP_LOGI(TAG, "add_station %s record: %d", (char *)SSID, read_station(SSID));
    /* Return the record number */
    return read_station(SSID);
}



int read_station(uint8_t *SSID)
{
    uint8_t     *dst = (uint8_t *)&wifiStation;
    static int	rc;
    FILE	*f;
    size_t	bytes;

    if ((SSID == NULL) || (strlen((char *)SSID) == 0)) {
	ESP_LOGI(TAG, "read_station(NULL)");
	return -1;
    }

    memset(dst, 0, sizeof(wifiStation));
    f = fopen("/spiffs/etc/stations.conf", "r+");
    if (f == NULL) {
	f = fopen("/spiffs/etc/stations.conf", "w+");
	fclose(f);
	ESP_LOGI(TAG, "/spiffs/etc/stations.conf created, return -1");
	return -1;
    }

    rc = 0;
    fseek(f, 0, SEEK_SET);

    while (1) {
        bytes = fread(dst, 1, sizeof(wifiStation), f);
	if (bytes < sizeof(wifiStation)) {
	    fclose(f);
	    memset(dst, 0, sizeof(wifiStation));
	    return -1;
	}
	if (strcmp(wifiStation.SSID, (char *)SSID) == 0) {
	    // Fount it
	    fclose(f);
	    return rc;
	}
	rc++;
    }
    return -1;
}



void remove_station(uint8_t *SSID)
{
    FILE        *n, *o;
    uint8_t     *dst;
    size_t      bytes;

    n = fopen("/spiffs/etc/stations.new", "a");
    if (n == NULL) {
        ESP_LOGE(TAG, "cannot create /spiffs/etc/stations.new");
        return;
    }
    o = fopen("/spiffs/etc/stations.conf", "r");
    if (o == NULL) {
        ESP_LOGE(TAG, "cannot open spiffs/etc/stations.conf for reading");
        fclose(n);
        return;
    }

    dst = (uint8_t*)&wifiStation;
    while (true) {
        bytes = fread(dst, 1, sizeof(wifiStation), o);
        if (bytes == 0)
            break;

        if ((strcmp((char *)SSID, wifiStation.SSID) == 0) || (strlen(wifiStation.SSID) == 0)) {
            // Record to delete, don't copy
        } else {
            fwrite(dst, 1, sizeof(wifiStation), n);
        }
    }
    fclose(o);
    fclose(n);

    rename("/spiffs/etc/stations.conf", "/spiffs/etc/stations.old");
    rename("/spiffs/etc/stations.new", "/spiffs/etc/stations.conf");
    unlink("/spiffs/etc/stations.old");
}



void write_runtime()
{
    uint8_t	*dst = (uint8_t *)&runtime;
    FILE	*f = fopen("/spiffs/etc/runtime.conf", "w+");

    if (f == NULL) {
	ESP_LOGE(TAG, "write /spiffs/etc/runtime.conf failed");
	return;
    }

    size_t bytes = fwrite(dst, 1, sizeof(runtime), f);
    fclose(f);
    if (bytes != sizeof(runtime)) {
	ESP_LOGE(TAG, "/spiffs/etc/runtime.conf written %d/%d bytes", bytes, sizeof(runtime));
    }
}



void read_runtime() 
{
    uint8_t	*dst;
    FILE	*f = fopen("/spiffs/etc/runtime.conf", "r");

    if (f == NULL) {
	// No runtime yet, create it.
	runtime.Version = 1;
	runtime.AutoModeStarted = false;
	runtime.StageResume = 0;
	runtime.StageTimeLeft = 0;
	runtime.HopAddition = 0;
	runtime.ManualMLT = 45.0;
	runtime.ManualHLT = 45.0;
	runtime.BrewStart = (time_t)0;
	runtime.Logfile[0] = '\0';
	runtime.PumpCooling = false;
	runtime.TimeBrewing = 0;
	runtime.MashStep = 0;
	runtime.MLT_usage = 0;
	runtime.HLT_usage = 0;
	write_runtime();
    } else {
	dst = (uint8_t*)&runtime;
	size_t bytes = fread(dst, 1, sizeof(runtime), f);
	fclose(f);
	if (bytes != sizeof(runtime)) {
	    ESP_LOGE(TAG, "/spiffs/etc/runtime.conf read %d/%d bytes", bytes, sizeof(runtime));
	    runtime.MLT_usage = 0;
	    runtime.HLT_usage = 0;
	}
#if 0
	printf("Auto started     %s\n", runtime.AutoModeStarted ? "yes":"no");
	printf("Stage resume     %d\n", runtime.StageResume);
	printf("Stage time left  %d\n", runtime.StageTimeLeft);
	printf("Hop addition     %d\n", runtime.HopAddition);
	printf("Brew start       %d\n", (int)runtime.BrewStart);
	printf("Log file         %s\n", runtime.Logfile);
	printf("Pump cooling     %s\n", runtime.PumpCooling ? "yes":"no");
	printf("Time brewing     %d\n", runtime.TimeBrewing);
#endif
    }
}



void append_recipe()
{
    uint8_t *dst = (uint8_t *)&recipe;
    FILE *f = fopen("/spiffs/etc/recipe.conf", "a");

    if (f == NULL) {
	ESP_LOGE(TAG, "append /spiffs/etc/recipe.conf failed");
	return;
    }

    size_t bytes = fwrite(dst, 1, recipe_hdr.recsize, f);
    fclose(f);
    ESP_LOGI(TAG, "/spiffs/etc/recipe.conf appended %d bytes", bytes);
}



void write_recipe(int RecNo)
{
    uint8_t     *dst = (uint8_t *)&recipe;
    FILE        *f = fopen("/spiffs/etc/recipe.conf", "r+");

    if (f == NULL) {
	ESP_LOGE(TAG, "write /spiffs/etc/recipe.conf failed");
	return;
    }

    fseek(f, (RecNo - 1) * recipe_hdr.recsize + recipe_hdr.hdrsize, SEEK_SET);
    size_t bytes = fwrite(dst, 1, recipe_hdr.recsize, f);
    fclose(f);
    if (bytes != recipe_hdr.recsize) {
	ESP_LOGE(TAG, "/spiffs/etc/recipe.conf write record %d, %u/%u bytes", RecNo, (unsigned)bytes, (unsigned)recipe_hdr.recsize);
    }
}



void read_recipe(int RecNo)
{
    uint8_t     *dst;
    size_t	bytes;
    FILE        *f = fopen("/spiffs/etc/recipe.conf", "r");

    if (f == NULL) {
	// No recipe yet, create it.
	dst = (uint8_t*)&recipe_hdr;
	memset(dst, 0, sizeof(recipe_hdr));
	recipe_hdr.version = RECIPE_VERSION;
	recipe_hdr.hdrsize = sizeof(recipe_hdr);
	recipe_hdr.recsize = sizeof(recipe);
	recipe_hdr.mashmax = MASH_MAX;
	recipe_hdr.additionmax = ADDITION_MAX;
	f = fopen("/spiffs/etc/recipe.conf", "w");
	bytes = fwrite(dst, 1, sizeof(recipe_hdr), f);
	if (bytes != sizeof(recipe_hdr)) {
	    ESP_LOGE(TAG, "/spiffs/etc/recipe.conf write header, %d/%d bytes", bytes, sizeof(recipe_hdr));
	}
	dst = (uint8_t*)&recipe;
	memset(dst, 0, sizeof(recipe));
	sprintf(recipe.Name, "Recipe 1");
	sprintf(recipe.Code, "001");
	sprintf(recipe.MashStep[0].Name, "Mash-in");
	recipe.MashStep[0].Type = MASHTYPE_INFUSION;
	recipe.MashStep[0].Step_temp = recipe.MashStep[0].End_temp = recipe.MashStep[0].Infuse_temp = 67.5;
	recipe.MashStep[0].Infuse_amount = 15.0;
	recipe.MashStep[0].Step_time = 1;
	recipe.MashStep[0].Ramp_time = 1;
	for (int i = 1; i < MASH_MAX; i++)
	    recipe.MashStep[i].Type = MASHTYPE_TEMPERATURE;
	sprintf(recipe.MashStep[1].Name, "Mash");
	recipe.MashStep[1].Step_temp = recipe.MashStep[1].End_temp = 67.0;
	recipe.MashStep[1].Step_time = 75;
	recipe.MashStep[1].Ramp_time = 1;
	sprintf(recipe.MashStep[2].Name, "Mash-out");
	recipe.MashStep[2].Step_temp = recipe.MashStep[2].End_temp = 78.0;
	recipe.MashStep[2].Step_time = 5;
	recipe.MashStep[2].Ramp_time = 11;
	recipe.Mashsteps = 3;
	recipe.BoilTime = 60;
	recipe.Additions = 2;
	sprintf(recipe.Addition[0].Name, "Hop");
	recipe.Addition[0].Time = 60;
	recipe.Addition[0].Type = ADDITION_HOP_BOIL;
	sprintf(recipe.Addition[1].Name, "Hop");
	recipe.Addition[1].Time = 10;
	recipe.Addition[1].Type = ADDITION_HOP_BOIL;
	recipe.CoolTemp = 20.0;
	recipe.Whirlpool9 = 0;
	recipe.Whirlpool7 = 0;
	recipe.Whirlpool6 = 0;
	recipe.Whirlpool2 = 0;
	recipe.SpargeTemp = 85.0;
	bytes = fwrite(dst, 1, sizeof(recipe), f);
	fclose(f);
    } else {
	/*
	 * Try to read the new file header
	 */
	dst = (uint8_t*)&recipe_hdr;
	fseek(f, 0, SEEK_SET);
	bytes = fread(dst, 1, sizeof(recipe_hdr), f);
	if (bytes != sizeof(recipe_hdr)) {
            ESP_LOGE(TAG, "/spiffs/etc/recipe.conf read header, %d/%d bytes", bytes, sizeof(recipe_hdr));
	    fclose(f);
	    return;
        }
/*
	if (recipe_hdr.version < RECIPE_VERSION) {
	    FILE        *nf = fopen("/spiffs/etc/recipe.new", "w");

	    ESP_LOGI(TAG, "/spiffs/etc/recipe.conf version %d, new %d", recipe_hdr.version, RECIPE_VERSION);

	    fseek(f, recipe_hdr.hdrsize, SEEK_SET);
	    dst = (uint8_t*)&recipe;
	    while ((bytes = fread(dst, 1, recipe_hdr.recsize, f))) {

		// Upgrade data here
		bytes = fwrite(dst, 1, sizeof(recipe), nf);
                if (bytes != sizeof(recipe)) {
		    ESP_LOGE(TAG, "/spiffs/etc/recipe.new write data, %d/%d bytes", bytes, sizeof(recipe));
            	}
	    }
	    // Update the header with new sizes
	    fclose(nf);
	    fclose(f);
	    rename("/spiffs/etc/recipe.conf", "/spiffs/etc/recipe.old");
	    rename("/spiffs/etc/recipe.new", "/spiffs/etc/recipe.conf");
	    unlink("/spiffs/etc/recipe.old");
	    f = fopen("/spiffs/etc/recipe.conf", "r");
	}
*/
	dst = (uint8_t*)&recipe;
	fseek(f, (RecNo - 1) * recipe_hdr.recsize + recipe_hdr.hdrsize, SEEK_SET);
	bytes = fread(dst, 1, sizeof(recipe), f);
	fclose(f);
	if (bytes != sizeof(recipe)) {
	    ESP_LOGE(TAG, "/spiffs/etc/recipe.conf read record %d, %d/%d bytes", RecNo, bytes, sizeof(recipe));
	}
    }
}



void delete_recipe(int RecNo)
{
    int         RecRead = 1, RecWrite = 1;
    FILE        *n, *o;
    uint8_t     *dst;
    size_t      bytes;

    n = fopen("/spiffs/etc/recipe.new", "a");
    if (n == NULL) {
        ESP_LOGE(TAG, "cannot create /spiffs/etc/recipe.new");
        return;
    }
    o = fopen("/spiffs/etc/recipe.conf", "r");
    if (o == NULL) {
        ESP_LOGE(TAG, "cannot open spiffs/etc/recipe.conf for reading");
        fclose(n);
        return;
    }

    dst = (uint8_t*)&recipe_hdr;
    fread(dst, 1, recipe_hdr.hdrsize, o);
    fwrite(dst, 1, recipe_hdr.hdrsize, n);

    dst = (uint8_t*)&recipe;
    while (true) {
        bytes = fread(dst, 1, recipe_hdr.recsize, o);
        if (bytes == 0)
            break;

        if (RecRead != RecNo) {
            // Record to copy
            if ((config.RecipeRec == RecRead) && (config.RecipeRec != RecWrite)) {
                // We need to change the default record.
                config.RecipeRec = RecWrite;
                write_config();
            }
            fwrite(dst, 1, recipe_hdr.recsize, n);
            RecWrite++;
        }
	RecRead++;
    }
    fclose(o);
    fclose(n);

    rename("/spiffs/etc/recipe.conf", "/spiffs/etc/recipe.old");
    rename("/spiffs/etc/recipe.new", "/spiffs/etc/recipe.conf");
    unlink("/spiffs/etc/recipe.old");
    ESP_LOGI(TAG, "Deleted recipe %d", RecNo);
}

mercurial