0

I'm trying to controll an AC unit but the issue is space - right now, I store the data like this:

consts PROGMEM unsigned int Signal_Heat_Fan0_Temp30[] = {233,636,17884,3032,8944,500,496,492,1496,524,472,548,452,544,448,552,444,552,444,548,444,552,444,552,1436,556,444,552,444,548,1440,552,472,524,472,520,1472,492,1496,520,1468,556,1436,552,1440,552,444,548,448,548,444,552,448,548,448,548,448,548,472,524,468,524,472,524,476,520,472,520,476,520,476,520,472,524,472,552,444,548,452,548,444,552,444,548,448,548,444,552,448,544,452,544,448,552,472,524,468,524,472,524,472,524,472,520,476,520,476,520,472,524,1468,552,1436,556,1436,556,1436,552,2944,3028,8920,548,1440,552,448,548,472,524,468,524,472,524,472,472,524,516,476,552,444,548,1444,552,444,548,448,552,440,556,440,556,1432,556,1440,548,452,544,1444,552,1464,524,1464,472,1520,524,1464,556,1436,552,1440,552,1436,556,440,552,448,548,444,552,1440,552,1440,552,1464,524,472,496,496,472,524,520,476,548,444,552,448,552,1440,548,1440,556,1432,556,1440,548,448,548,444,552,448,548,472,524,472,524,1464,472,524,472,524,516,476,552,444,552,444,552,1440,552,1440,552,1436,556,1436,552};
consts PROGMEM unsigned int Signal_Heat_Fan0_Temp29[] = {233,636,17896,3032,8916,552,468,524,1468,524,468,500,496,472,528,520,476,544,448,552,444,552,444,548,1440,556,440,552,448,548,1440,552,444,548,452,544,1444,548,1468,524,1464,472,1520,520,1468,552,444,552,448,548,444,552,444,548,448,548,444,552,444,556,444,548,448,548,444,552,448,544,472,524,472,524,472,524,472,468,528,520,476,544,448,552,444,552,444,548,444,556,440,556,444,548,448,548,444,552,444,552,444,548,452,544,476,524,472,524,468,524,472,492,1496,520,1472,548,1440,556,1440,548,2944,3032,8916,552,1436,552,444,552,444,548,452,544,448,548,476,524,468,524,472,524,472,492,1496,520,476,524,472,548,448,552,444,552,1440,548,1440,548,448,548,1440,556,1440,548,1440,552,1464,524,1464,500,1496,520,1468,552,1440,548,444,556,444,552,444,548,1440,552,1440,548,1444,544,476,524,472,524,472,524,468,524,472,492,1496,524,476,548,1444,548,1440,548,1444,552,444,552,444,548,448,548,444,552,448,544,1448,544,476,524,468,524,472,524,472,492,504,516,1472,548,1444,552,1440,548,1440,548};
consts PROGMEM unsigned int Signal_Heat_Fan0_Temp28[] = {233,636,17880,3056,8912,524,476,544,1444,552,444,548,448,552,440,556,440,556,444,552,444,548,444,552,1440,552,444,552,468,524,1468,524,468,472,524,520,1476,544,1444,548,1440,556,1432,556,1440,548,448,548,444,552,448,548,448,548,472,524,472,520,472,524,472,496,500,472,524,492,504,544,452,548,444,552,444,552,444,548,448,552,440,556,444,548,448,548,444,552,448,544,452,544,476,524,472,524,468,524,472,524,472,492,500,520,476,548,452,544,448,552,444,552,1440,548,1440,552,1440,552,1440,548,2944,3028,8924,544,1444,552,468,524,472,496,500,492,504,516,476,552,444,548,452,548,444,552,1440,548,444,552,444,552,1444,548,444,552,1440,548,1444,544,476,520,1472,492,1496,520,1468,552,1444,548,1440,552,1436,552,1440,552,1440,552,444,548,452,544,476,520,1468,524,1468,492,1496,520,480,544,448,548,448,552,444,548,444,552,444,548,452,548,1440,552,1436,552,1444,544,476,520,476,524,468,524,472,496,500,492,1496,524,476,544,452,548,444,552,444,548,448,548,1444,548,1440,552,1440,548,1444,520};
consts PROGMEM unsigned int Signal_Heat_Fan0_Temp27[] = {233,640,17892,3032,8916,552,448,548,1464,528,468,528,468,468,528,468,528,520,472,552,444,552,444,552,1440,548,448,548,444,556,1436,552,444,552,444,552,1436,552,1444,548,1468,492,1496,472,1516,552,448,548,448,548,448,548,444,552,444,552,444,552,440,556,444,552,444,548,444,552,448,548,448,548,472,524,472,524,468,468,528,472,524,520,472,524,472,552,448,548,448,548,444,552,444,548,448,548,444,556,440,552,448,548,444,552,444,552,448,544,472,524,472,528,1464,468,1520,520,1472,552,1436,556,2944,3028,8912,556,1440,548,448,548,444,552,448,548,448,548,444,552,472,520,472,524,472,524,1464,472,528,488,508,544,448,552,444,552,1436,556,1436,552,448,548,1440,548,1440,556,1440,548,1440,552,1464,524,1464,472,1524,544,1444,552,444,552,448,548,444,552,1440,548,1440,552,1444,548,444,552,448,544,472,524,472,524,468,500,1492,492,1500,548,452,544,1440,556,1436,552,444,552,444,552,444,548,448,548,448,548,1444,548,472,524,468,524,472,524,472,472,528,468,1520,520,1468,552,1440,552,1436,552};
consts PROGMEM unsigned int Signal_Heat_Fan0_Temp26[] = {233,640,17884,2980,8992,528,472,524,1464,472,524,520,476,548,444,556,440,556,444,548,444,552,444,552,1440,552,440,556,444,548,1440,552,444,552,468,524,1468,528,1460,472,1520,548,1444,548,1440,556,444,548,448,548,444,552,444,552,444,552,444,552,444,552,444,548,448,548,472,524,468,524,472,472,528,468,528,488,504,548,448,552,444,548,444,556,440,556,444,548,444,552,444,552,444,548,448,548,448,552,444,548,448,548,472,524,472,520,472,524,472,472,524,520,1468,548,1444,552,1440,552,1436,556,2944,3024,8920,552,1440,552,444,548,444,552,448,548,468,524,472,528,472,468,524,468,528,520,1472,548,444,556,444,548,1440,552,444,548,1440,556,1440,548,444,552,1440,548,1444,552,1464,492,1496,520,1472,548,1440,556,1440,548,1440,552,444,552,444,552,444,548,1440,552,1444,548,1440,548,472,524,472,472,524,472,520,520,480,544,452,548,1440,548,448,548,1440,552,1440,552,444,548,448,548,448,552,444,552,468,524,1464,524,472,472,528,468,524,468,528,544,452,548,1440,556,1436,552,1440,548,1440,556};
consts PROGMEM unsigned int Signal_Heat_Fan0_Temp25[] = {233,644,17892,3028,8916,552,444,548,1440,556,440,552,448,548,444,552,444,548,448,548,448,548,472,528,1464,468,528,520,472,548,1448,544,444,556,440,556,1440,548,1440,548,1440,556,1440,548,1440,552,448,544,472,528,472,524,468,468,528,468,528,544,448,552,444,552,444,552,444,552,444,552,444,552,444,548,444,552,444,552,444,552,448,548,444,552,468,524,472,524,472,524,468,472,524,472,528,520,476,544,448,552,444,548,448,548,444,556,440,556,444,548,444,552,1440,548,1440,556,1440,548,1468,548,2920,3052,8920,472,1516,548,452,548,444,552,444,548,448,548,444,556,440,556,444,548,448,548,1440,548,452,544,448,552,1440,548,472,524,1464,472,1516,552,448,544,1444,552,1444,548,1440,552,1436,552,1440,552,1440,552,1440,548,1464,528,472,496,500,468,524,520,1472,548,1440,556,1436,552,444,552,444,556,440,552,444,552,444,552,1436,552,448,544,452,548,1468,524,1464,468,528,520,472,552,448,548,448,548,448,548,1440,548,448,548,444,552,444,556,444,548,444,552,1440,548,1440,552,1464,500,1496,548};

The first item is the length of the array and the rest is data I can send with IRemote library with the raw send libray. I've mapped most of the buttons and now I'm at

Sketch uses 95.286 bytes of program storage space

Is there a better encoding that could take less space? I'd like to add at least 3 times more commands to the Sketch, but I'm already at 37% on an Arduino Mega.

I know ideally I should generate the array, not store it, but I haven't gotten that far (yet, I'm working on it) and for me this is an interesting issue.

Thank you!


Edit 1: Code uploaded on GitHub - https://github.com/vladbabii/SamsungACIrControll/tree/master/AC_IrControll

7
  • What do the numbers represent?
    – Majenko
    Commented Sep 1, 2015 at 23:03
  • The sequence of 0 and 1 time-encoded that make up an IR transmission to set something. The lines in the post are for heat mode, and temperature 25 to 30. I read the data with an IR sensor from the AC remote, and resend it to control the AC. In this case I am using IRemote library, but there is also IRLib. There are alot of tutorials and demos on youtube if you want to see how it works, but if you want I can post more code.
    – vlad b.
    Commented Sep 1, 2015 at 23:06
  • I thought so. So the times don't have to be 100% accurate then I guess - you just have a set number of "ballpark" figures - around 500, around 1500, around 3000, etc. Do you really need to store the actual times in that case, or just a representation of the time?
    – Majenko
    Commented Sep 1, 2015 at 23:08
  • 1
    It looks like there's a standard preamble of ~600, ~1800, ~3000, ~9000 and then a sequence of ~500 and ~!500 to represent 0 and 1, and that makes it even easier
    – Majenko
    Commented Sep 1, 2015 at 23:11
  • So i should find sequences of numbers that appear often in the code and just save that as a number. The timings do not have to be 100% accurate, I did 10 reading of each value, stored to logs, then did the average with a script to get the current options. I could modify the script to search for patterns and find what numbers never appear anywhere and generate a map for that... Thank you for the idea!
    – vlad b.
    Commented Sep 1, 2015 at 23:13

3 Answers 3

2

I have analysed your codes with a small Lua script:

function pairsByKeys (t, f)
  local a = {}
  -- build temporary table of the keys
  for n in pairs (t) do
    table.insert (a, n)
  end
  table.sort (a, f)  -- sort using supplied function, if any
  local i = 0        -- iterator variable
  return function () -- iterator function
    i = i + 1
    return a[i], t[a[i]]
  end  -- iterator function
end -- pairsByKeys


nums = {233,636,17884,3032,8944,
-- and so on ... 
548,444,552,444,556,444,548,444,552,1440,548,1440,552,1464,500,1496,548}

uniq = { }

for k, v in ipairs (nums) do
  if uniq [v] then
    uniq [v] = uniq [v] + 1
  else
    uniq [v] = 1
  end -- else
end -- for

count = 0

for k, v in pairsByKeys (uniq) do
  print (string.format ("%8i = %3i", k, v))
  count = count + 1
end


print ("count = ", count)

Results:

     233 =   6
     440 =  18
     444 = 154
     448 =  86
     452 =  20
     468 =  42
     472 = 103
     476 =  27
     480 =   2
     488 =   2
     492 =  15
     496 =   8
     500 =  10
     504 =   4
     508 =   1
     516 =   4
     520 =  41
     524 =  97
     528 =  26
     544 =  39
     548 = 189
     552 = 196
     556 =  56
     636 =   3
     640 =   2
     644 =   1
    1432 =   3
    1436 =  24
    1440 =  91
    1444 =  26
    1448 =   2
    1460 =   1
    1464 =  21
    1468 =  16
    1472 =   8
    1476 =   1
    1492 =   1
    1496 =  12
    1500 =   1
    1516 =   3
    1520 =   5
    1524 =   1
    2920 =   1
    2944 =   5
    2980 =   1
    3024 =   1
    3028 =   4
    3032 =   4
    3052 =   1
    3056 =   1
    8912 =   2
    8916 =   4
    8920 =   3
    8924 =   1
    8944 =   1
    8992 =   1
   17880 =   1
   17884 =   2
   17892 =   2
   17896 =   1
count =     60

Assuming there is some jitter I rounded them to the nearest 50:

for k, v in ipairs (nums) do

  v = math.floor (v / 50)    -- <--- add this
  v = v * 50                 -- <--- add this
  if uniq [v] then
    uniq [v] = uniq [v] + 1
  else
    uniq [v] = 1
  end -- else
end -- for

Results:

     200 =   6
     400 = 258
     450 = 219
     500 = 411
     550 = 252
     600 =   6
    1400 = 146
    1450 =  60
    1500 =  10
    2900 =   6
    2950 =   1
    3000 =   9
    3050 =   2
    8900 =  11
    8950 =   1
   17850 =   6
count =     16

So, 16 different lengths.


So now you can use 4 bits per code (and a lookup table) rather than 16 bits.

Also see TV-B-Gone design notes for how they compressed the IR codes for lots of TV brands into a small table in an ATtiny85.

2
  • I think you can safely replace all values with either 500 or 1400 (except for the preamble). So you can store them in 1 bit per code. Secondly the first 118 values seem to be identical, and after those values there seems to be another preamble (?). After this another 26 values are identical. So you could store the first part (146 values) only once. (Also try leaving it out completely and see if the AC unit still accepts it)
    – Gerben
    Commented Sep 2, 2015 at 8:10
  • 1
    Good idea. We'll have it down to a few dozen bytes soon. :)
    – Nick Gammon
    Commented Sep 2, 2015 at 11:32
1

Do you need all of the data accessible at once? How about storing it on a file device or external memory? SDcards are slow but huge. FRAM devices a fast but not as huge and typically aren't formatted for a file system. They act more like an independent memory space accessed by a function. (The Adafruit product is one example; I'm sure there are more).

2
  • It's a good idea to use FRAM or something simillar. Havent thought of that yet, I will look into it. I only need to be able to fetch one row at a time to send it over IR.
    – vlad b.
    Commented Sep 1, 2015 at 22:26
  • Then an external memory device should work well for you.
    – JRobert
    Commented Sep 1, 2015 at 23:27
1

Another form of storage is the EEPROM. There are between 512 bytes and 4K of EEPROM per Arduino, depending on the model of Arduino - see https://www.arduino.cc/en/Reference/EEPROM

EEPROM is persistent when the power gets cut, and MAY or may not be overwritten when the program is changed - I have not tried. If it is not overwritten, you can write a sketch just to set it, then overwrite it with your IR sketch; otherwise, you may have to set up some way to "upload" the data into your sketch (e.g. if you press a special button, it will listen on the serial port, any bytes it reads it will write to the EEPROM.

If you have an ISP (aka ICSP) programmer such as the USBasp (see google), which are very inexpensive, then you can read/write the EEPROM directly - all you need is 6 pins exposed. You can also use the USBasp to reprogram an AtMega/AtTiny which is not on an Arduino board (this also gives you a little extra program space, since it no longer requires a bootloader).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.