10

I'm making a smart home system using nodeMCU, and I need to store and retrieve data from the module. I used the following function.

function save_settings(name,value)
  file.remove(name)
  file.open(name,"w+")
  file.writeline(value)
  file.close()
end

It works but it's slow and the NodeMCU crashes if I trigger the above function rapidly... Sometimes requiring a FS format to be able to use it again.

So my question is: is there any other way to make variables persistent between restarts?

dda
  • 6,030
  • 2
  • 25
  • 34
Suraj Bhawal
  • 403
  • 1
  • 6
  • 19
  • each write probably requires a block of flash to be erased and rewritten, which is inherently slow. I have no idea why it would crash, but it could be overflowing the write buffer or trying to erase/write a page while the same operation is already happening. In either case the solution may be to buffer the data in an array somewhere and write less often. If that's not good enough you may need to write to an SPI EEPROM or SD card :( – user1816847 Oct 04 '15 at 18:59
  • @user1816847 Ithx for the reply but that's no longer an option because i already made a cuatom pcb for the project and currently using it without the save feature... All i can do now is some home implement a save load feature through software only.. – Suraj Bhawal Oct 04 '15 at 19:02
  • I'd recommend removing the `file.remove(name)` as it is redundant with the `file.open` in this case due to the `w+` mode. This may also simplify the work the FS has to do since there is no change to the file table. – Adam B Mar 29 '16 at 23:53

2 Answers2

6

I'm using the latest firmware, 0.9.6-dev_20150704, the float version (https://github.com/nodemcu/nodemcu-firmware/releases)

This code took 62-63 ms to complete at first, and seems to add a few fractions of a millisecond with each successive run of the code, after a few hundred executions, it was up to almost 100 ms. It never crashed on me.

function save_setting(name, value)
  file.open(name, 'w') -- you don't need to do file.remove if you use the 'w' method of writing
  file.writeline(value)
  file.close()
end

function read_setting(name)
  if (file.open(name)~=nil) then
      result = string.sub(file.readline(), 1, -2) -- to remove newline character
      file.close()
      return true, result
  else
      return false, nil
  end
end

startTime = tmr.now()

test1 = 1200
test2 = 15.7
test3 = 75
test4 = 15000001
save_setting('test1', test1)
save_setting('test2', test2)
save_setting('test3', test3)
save_setting('test4', test4)

1exists, test1 = read_setting('test1')
2exists, test2 = read_setting('test2')
3exists, test3 = read_setting('test3')
4exists, test4 = read_setting('test4')

completeTime = (tmr.now()-startTime)/(1000)
print('time to complete (ms):')
print(tostring(completeTime))
wordsforthewise
  • 13,746
  • 5
  • 87
  • 117
  • 1
    in the read_setting function, you have file.readline(value) - this should probably be just file.readline() as value shouldn't exist in that context. – askvictor Mar 07 '16 at 04:57
  • Also, I'd add a check to see if the open() call succeeded - if it returns nil, then the read_setting function should return nil. – askvictor Mar 07 '16 at 05:00
  • 1
    a shorter form to remove new line is `file.readline():match("[^\n]*")` – rodvlopes Sep 16 '17 at 19:01
3

If you upgrade to the newer version (based on SDK 1.4.0) you can use the rtcmem memory slots:

local offset = 10
local val = rtcmem.read32(offset, 1)
rtcmem.write32(offset, val + 1)

That memory is documented to persist through a deep sleep cycle; I've found it to persist across both hardware and software resets (but not cycling power.)

Mark McGinty
  • 756
  • 7
  • 13