somfy.lua 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. -- Somfy module example (beside somfy module requires also SJSON module)
  2. -- The rolling code number is stored in the file somfy.cfg.
  3. -- A cached write of the somfy.cfg file is implemented in order to reduce
  4. -- the number of write to the EEPROM memory. Together with the logic of the
  5. -- file module it should allow long lasting operation.
  6. local config_file = "somfy."
  7. local config, config_saved
  8. -- somfy.cfg looks like
  9. -- {"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}}
  10. local tmr_cache = tmr.create()
  11. local tmr_delay = tmr.create()
  12. local pin = 4
  13. local function deepcopy(orig)
  14. local orig_type = type(orig)
  15. local copy
  16. if orig_type == 'table' then
  17. copy = {}
  18. for orig_key, orig_value in next, orig, nil do
  19. copy[deepcopy(orig_key)] = deepcopy(orig_value)
  20. end
  21. setmetatable(copy, deepcopy(getmetatable(orig)))
  22. else -- number, string, boolean, etc
  23. copy = orig
  24. end
  25. return copy
  26. end
  27. local function readconfig()
  28. local ln
  29. if file.exists(config_file.."cfg") then
  30. print("Reading config from "..config_file.."cfg")
  31. file.open(config_file.."cfg", "r+")
  32. ln = file.readline()
  33. file.close()
  34. else
  35. if file.exists(config_file.."bak") then
  36. print("Reading config from "..config_file.."bak")
  37. file.open(config_file.."bak", "r+")
  38. ln = file.readline()
  39. file.close()
  40. end
  41. end
  42. if not ln then ln = "{}" end
  43. print("Configuration: "..ln)
  44. config = sjson.decode(ln)
  45. config_saved = deepcopy(config)
  46. end
  47. local function writeconfighard()
  48. print("Saving config")
  49. file.remove(config_file.."bak")
  50. file.rename(config_file.."cfg", config_file.."bak")
  51. file.open(config_file.."cfg", "w+")
  52. local ok, cfg = pcall(sjson.encode, config)
  53. if ok then
  54. file.writeline(cfg)
  55. else
  56. print("Config not saved!")
  57. end
  58. file.close()
  59. config_saved = deepcopy(config)
  60. end
  61. local function writeconfig()
  62. tmr_cache:stop()
  63. local savenow = false
  64. local savelater = false
  65. --print("Config: "..sjson.encode(config))
  66. --print("Config saved: "..sjson.encode(config))
  67. local count = 0
  68. for _ in pairs(config_saved) do count = count + 1 end
  69. if count == 0 then
  70. config_saved = readconfig()
  71. end
  72. for remote,cfg in pairs(config_saved) do
  73. savelater = savelater or not config[remote] or config[remote].rc > cfg.rc
  74. savenow = savenow or not config[remote] or config[remote].rc > cfg.rc + 10
  75. end
  76. savelater = savelater and not savenow
  77. if savenow then
  78. print("Saving config now!")
  79. writeconfighard()
  80. end
  81. if savelater then
  82. print("Saving config later")
  83. tmr_cache:alarm(65000, tmr.ALARM_SINGLE, writeconfighard)
  84. end
  85. end
  86. --======================================================================================================--
  87. local function wait(ms, cb, par)
  88. par = par or {}
  89. print("wait: ".. ms)
  90. if cb then tmr_delay:alarm(ms, tmr.ALARM_SINGLE, function () cb(unpack(par)) end) end
  91. end
  92. local function down(remote, cb, par)
  93. par = par or {}
  94. print("down: ".. remote)
  95. config[remote].rc=config[remote].rc+1
  96. somfy.sendcommand(pin, config[remote].address, somfy.DOWN, config[remote].rc, 16, function() wait(100, cb, par) end)
  97. writeconfig()
  98. end
  99. local function up(remote, cb, par)
  100. par = par or {}
  101. print("up: ".. remote)
  102. config[remote].rc=config[remote].rc+1
  103. somfy.sendcommand(pin, config[remote].address, somfy.UP, config[remote].rc, 16, function() wait(100, cb, par) end)
  104. writeconfig()
  105. end
  106. local function downStep(remote, cb, par)
  107. par = par or {}
  108. print("downStep: ".. remote)
  109. config[remote].rc=config[remote].rc+1
  110. somfy.sendcommand(pin, config[remote].address, somfy.DOWN, config[remote].rc, 2, function() wait(300, cb, par) end)
  111. writeconfig()
  112. end
  113. local function upStep(remote, cb, par) -- luacheck: ignore
  114. par = par or {}
  115. print("upStep: ".. remote)
  116. config[remote].rc=config[remote].rc+1
  117. somfy.sendcommand(pin, config[remote].address, somfy.UP, config[remote].rc, 2, function() wait(300, cb, par) end)
  118. writeconfig()
  119. end
  120. --======================================================================================================--
  121. gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP)
  122. if not config then readconfig() end
  123. if #config == 0 then -- somfy.cfg does not exist
  124. config = sjson.decode([[{"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}}]])
  125. config_saved = deepcopy(config)
  126. end
  127. down('window1',
  128. wait, {60000,
  129. up, {'window1',
  130. wait, {9000,
  131. downStep, {'window1',
  132. downStep, {'window1',
  133. downStep, {'window1',
  134. downStep, {'window1',
  135. downStep, {'window1',
  136. downStep, {'window1',
  137. downStep, {'window1'
  138. }}}}}}}}}})