ESP Home Write measured values to FLASH memory at specified time

Hello community :smiley:

I have another slightly complex question that I’m currently struggling with.

I’m currently working on the control system for my 3-chamber sewage treatment plant, as the old control system has seen better days.

I’m faced with the problem that I have to write setpoints to the FLASH memory after changing them, as well as several timers.

For the setpoints, I use → preferences: flash_write_interval: 1 min

so that they are applied 10 seconds after the change.

However, to conserve memory, I would like to write the timers to the FLASH only every 24 hours, but as it stands, this is not possible because ESPHome does not allow you to set different intervals for writing to the FLASH.

Have you ever solved something like this or can you help me?

I would prefer the following logic:

Write setpoints to FLASH 10 seconds after change.

Write timer values to FLASH every 24 hours.

Thanks in advance :slight_smile:

How offen do you expect to change the setpoints? :thinking:

You are aware that if the value does not change it will not be written again to flash? :writing_hand:

It’s likely not worth to spend too much effort to this, the system is quite sophisticated and I don’t remember any case here on this forum where someone destroyed the flash with default 1min interval.

If you have fwi one minute, esphome writes states to flash every one min (not after 10s) only if they have changed.

The timers are counted in minutes and must also be available in minutes. If these values are lost for one day, it is not a big deal, so I would like to write these values only every 24 hours and store them in RAM beforehand.

The setpoints values are already being saved, as I am working with → preferences: flash_write_interval: 10 sec.

However, I can’t get it to work so that when a timer expires after 1440 minutes (24 hours), the timer values are also written to the FLASH.

I could post my code, but I don’t think you want to read 1200 lines ^^

If you want, I can copy out the lines that I currently have and use.

Since the ESP can only handle about 100,000 FLASH write cycles and is usually done after that, I want to keep the write accesses as low as possible.

The setpoints are actually only changed a maximum of twice a year, so I’m not interested in these accesses, as there are only 10 variables.

When it expires, write your timer values to global variable which has
restore_value: yes .
This way It’s saved to flash every 1440minutes (if value has changed).

Cycles, not flash writes. One cycle is in range of 1000 component state changes …

1 Like

That’s what I’m doing right now ^^ Unfortunately without success -.-

I’ve copied the relevant sections of my code; maybe you can see where the error lies.

Thank you very much in advance for your help and time.

Code:


#####################################################
# Schreiben in den Flash
##################################################### 

preferences:
  flash_write_interval: 40s     # Only for testing!!!



globals:
  # Phase-Minuten Gesamt (werden nach Neustart wiederhergestellt)
  - id: phase1_beschickung_total
    type: uint32_t
    restore_value: true
  - id: phase2_belueftung_total
    type: uint32_t
    restore_value: true
  - id: phase3_absetz_total
    type: uint32_t
    restore_value: true
  - id: phase4_ablauf_total
    type: uint32_t
    restore_value: true
  - id: phase5_uess_total
    type: uint32_t
    restore_value: true
  - id: phase6_zykluspause_total
    type: uint32_t
    restore_value: true

  # Timer zum schreiben in den FLASH Speicher
  - id: flush_minutes_counter
    type: uint32_t
    restore_value: false



#####################################################
# Phase-Maschine: 
#####################################################
interval:
  - interval: 1s
    then:
      - lambda: |-

          // ---------------------------------------------------------
          // 6) LAUFZEIT DER PHASEN MINUTENWEISE AUFZÄHLEN     -> Block 6 von 8 welcher die Timer/ Counter enthält
          // ---------------------------------------------------------
          static uint32_t last_runtime_inc = 0;
          if (!id(var_testmodus_active) && id(var_aktuelle_phase) > 0 && id(var_aktuelle_phase) <= 6) {
              if (now - last_runtime_inc >= 60000) {
                  last_runtime_inc = now;
                  switch (id(var_aktuelle_phase)) {
                      case 1: id(phase1_beschickung_ram)++; break;
                      case 2: id(phase2_belueftung_ram)++; break;
                      case 3: id(phase3_absetz_ram)++; break;
                      case 4: id(phase4_ablauf_ram)++; break;
                      case 5: id(phase5_uess_ram)++; break;
                      case 6: id(phase6_zykluspause_ram)++; break;
                  }

                  // 24h-Zähler erhöhen
                  id(flush_minutes_counter)++;
                  //  DEBUG (1x pro Minute)
                  ESP_LOGD("daily", "flush_minutes_counter=%u", id(flush_minutes_counter));

                  // 24h erreicht → Flush -> zum Testen auf 15 Minuten gesetzt!!!!
                  if (id(flush_minutes_counter) >= 15) {
                    ESP_LOGI("daily", "24h erreicht → Tages-Flush");
                    id(do_daily_flush).execute();

                  }
              }
          }



#####################################################
# Flush Script: alle 24h 
#####################################################
script:
  - id: do_daily_flush
    mode: single
    then:
      - lambda: |-
          ESP_LOGD("daily", "Flush gestartet: speichere RAM-Minuten in persistente Totals...");
      - globals.set:
          id: phase1_beschickung_total
          value: !lambda 'return id(phase1_beschickung_total) + id(phase1_beschickung_ram);'
      - globals.set:
          id: phase2_belueftung_total
          value: !lambda 'return id(phase2_belueftung_total) + id(phase2_belueftung_ram);'
      - globals.set:
          id: phase3_absetz_total
          value: !lambda 'return id(phase3_absetz_total) + id(phase3_absetz_ram);'
      - globals.set:
          id: phase4_ablauf_total
          value: !lambda 'return id(phase4_ablauf_total) + id(phase4_ablauf_ram);'
      - globals.set:
          id: phase5_uess_total
          value: !lambda 'return id(phase5_uess_total) + id(phase5_uess_ram);'
      - globals.set:
          id: phase6_zykluspause_total
          value: !lambda 'return id(phase6_zykluspause_total) + id(phase6_zykluspause_ram);'
      - lambda: |-
          // Reset RAM counters + reset 24h counter
          id(phase1_beschickung_ram) = 0;
          id(phase2_belueftung_ram) = 0;
          id(phase3_absetz_ram) = 0;
          id(phase4_ablauf_ram) = 0;
          id(phase5_uess_ram) = 0;
          id(phase6_zykluspause_ram) = 0;
          id(flush_minutes_counter) = 0;
          ESP_LOGD("daily","Flush fertig - RAM-Zähler + flush counter zurückgesetzt.");

Not easy task for me.
At least tell what the error causes, what’s the output, misbehavior.

Phew, that’s hard to describe, because if I knew the “outcome,” I might be able to fix the error :smiley:

I can only describe what is not being done :confused:

The counters that store the operating time of the individual relays and save them in RAM are working (not included in my code snippet).

As long as the ESP is supplied with power, they count up.

To ensure that these values are stored, they should be written to the FLASH once a day so that in the event of a power failure, a maximum of 1 day’s worth of values is missing.

However, I don’t have any log output or anything else that would indicate an error, so I suspect that the code snippet is not being executed properly and/or that I have forgotten an essential part of the storage process or overlooked it in the ESP Home documentation.

So you mean that the values with your actual code are not saved in flash?

Yes, that’s right, with the current code, the variables (timer times) are not written to the FLASH.

After 49 hours of operation, I disconnected the ESP from the power supply, waited 10 minutes, and reconnected it.

Normally, it should now load the values last written to the FLASH, but it starts at 0.

I don’t see the error. Have you been observing the logs?

Not sure where your RAM entities are coming from are they a sensor? If so should they not have state on the end when you refer to them in lambdas?


id(phase4_ablauf_ram).state

100,000 cycles divided by 1440 minutes is how many years?

Best put battery backup on your counting device or write to a database over a network to conserve those counts. Oh wait, doesn’t HomeAssistant do that?

Lambda not working?

I will find time over the Christmas holidays to take another close look at the code and the logs to see if I can find anything.

As for storing data and values via Home Assistant, this is more of a “nice to have” feature.

The controller is programmed via ESP Home, but then has to work “stand alone.”

To maintain the system and change setpoints if necessary, you can access it via the web server or the specially created WiFi access.