state_spec.rb 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. require 'api_client'
  2. require './helpers/state_helpers'
  3. RSpec.configure do |c|
  4. c.include StateHelpers
  5. end
  6. RSpec.describe 'State' do
  7. before(:all) do
  8. @client = ApiClient.new(ENV.fetch('ESPMH_HOSTNAME'), ENV.fetch('ESPMH_TEST_DEVICE_ID_BASE'))
  9. @client.upload_json('/settings', 'settings.json')
  10. end
  11. before(:each) do
  12. @id_params = {
  13. id: @client.generate_id,
  14. type: 'rgb_cct',
  15. group_id: 1
  16. }
  17. @client.delete_state(@id_params)
  18. end
  19. context 'toggle command' do
  20. it 'should toggle ON to OFF' do
  21. init_state = @client.patch_state({'status' => 'ON'}, @id_params)
  22. expect(init_state['status']).to eq('ON')
  23. next_state = @client.patch_state({'command' => 'toggle'}, @id_params)
  24. expect(next_state['status']).to eq('OFF')
  25. end
  26. it 'should toggle OFF to ON' do
  27. init_state = @client.patch_state({'status' => 'OFF'}, @id_params)
  28. expect(init_state['status']).to eq('OFF')
  29. next_state = @client.patch_state({'command' => 'toggle'}, @id_params)
  30. expect(next_state['status']).to eq('ON')
  31. end
  32. end
  33. context 'deleting' do
  34. it 'should support deleting state' do
  35. desired_state = {
  36. 'status' => 'ON',
  37. 'level' => 10,
  38. 'hue' => 49,
  39. 'saturation' => 20
  40. }
  41. @client.patch_state(desired_state, @id_params)
  42. resulting_state = @client.get_state(@id_params)
  43. expect(resulting_state).to_not be_empty
  44. @client.delete_state(@id_params)
  45. resulting_state = @client.get_state(@id_params)
  46. expect(resulting_state).to be_empty
  47. end
  48. end
  49. context 'persistence' do
  50. it 'should persist parameters' do
  51. desired_state = {
  52. 'status' => 'ON',
  53. 'level' => 100,
  54. 'hue' => 0,
  55. 'saturation' => 100
  56. }
  57. @client.patch_state(desired_state, @id_params)
  58. patched_state = @client.get_state(@id_params)
  59. states_are_equal(desired_state, patched_state)
  60. desired_state = {
  61. 'status' => 'ON',
  62. 'level' => 10,
  63. 'hue' => 49,
  64. 'saturation' => 20
  65. }
  66. @client.patch_state(desired_state, @id_params)
  67. patched_state = @client.get_state(@id_params)
  68. states_are_equal(desired_state, patched_state)
  69. end
  70. it 'should affect member groups when changing group 0' do
  71. group_0_params = @id_params.merge(group_id: 0)
  72. desired_state = {
  73. 'status' => 'ON',
  74. 'level' => 100,
  75. 'hue' => 0,
  76. 'saturation' => 100
  77. }
  78. @client.patch_state(desired_state, group_0_params)
  79. individual_state = desired_state.merge('level' => 10)
  80. patched_state = @client.patch_state(individual_state, @id_params)
  81. expect(patched_state).to_not eq(desired_state)
  82. states_are_equal(individual_state, patched_state)
  83. group_4_state = @client.get_state(group_0_params.merge(group_id: 4))
  84. states_are_equal(desired_state, group_4_state)
  85. @client.patch_state(desired_state, group_0_params)
  86. group_1_state = @client.get_state(group_0_params.merge(group_id: 1))
  87. states_are_equal(desired_state, group_1_state)
  88. end
  89. it 'should keep group 0 state' do
  90. group_0_params = @id_params.merge(group_id: 0)
  91. desired_state = {
  92. 'status' => 'ON',
  93. 'level' => 100,
  94. 'hue' => 0,
  95. 'saturation' => 100
  96. }
  97. patched_state = @client.patch_state(desired_state, group_0_params)
  98. states_are_equal(desired_state, patched_state)
  99. end
  100. it 'should clear group 0 state after member group state changes' do
  101. group_0_params = @id_params.merge(group_id: 0)
  102. desired_state = {
  103. 'status' => 'ON',
  104. 'level' => 100,
  105. 'kelvin' => 100
  106. }
  107. @client.patch_state(desired_state, group_0_params)
  108. @client.patch_state(desired_state.merge('kelvin' => 10), @id_params)
  109. resulting_state = @client.get_state(group_0_params)
  110. expect(resulting_state.keys).to_not include('kelvin')
  111. states_are_equal(desired_state.reject { |x| x == 'kelvin' }, resulting_state)
  112. end
  113. it 'should not clear group 0 state when updating member group state if value is the same' do
  114. group_0_params = @id_params.merge(group_id: 0)
  115. desired_state = {
  116. 'status' => 'ON',
  117. 'level' => 100,
  118. 'kelvin' => 100
  119. }
  120. @client.patch_state(desired_state, group_0_params)
  121. @client.patch_state(desired_state.merge('kelvin' => 100), @id_params)
  122. resulting_state = @client.get_state(group_0_params)
  123. expect(resulting_state).to include('kelvin')
  124. states_are_equal(desired_state, resulting_state)
  125. end
  126. it 'changing member state mode and then changing level should preserve group 0 brightness for original mode' do
  127. group_0_params = @id_params.merge(group_id: 0)
  128. desired_state = {
  129. 'status' => 'ON',
  130. 'level' => 100,
  131. 'hue' => 0,
  132. 'saturation' => 100
  133. }
  134. @client.delete_state(group_0_params)
  135. @client.patch_state(desired_state, group_0_params)
  136. # color -> white mode. should not have brightness because brightness will
  137. # have been previously unknown to group 0.
  138. @client.patch_state(desired_state.merge('color_temp' => 253, 'level' => 11), @id_params)
  139. resulting_state = @client.get_state(group_0_params)
  140. expect(resulting_state.keys).to_not include('level')
  141. # color -> effect mode. same as above
  142. @client.patch_state(desired_state, group_0_params)
  143. @client.patch_state(desired_state.merge('mode' => 0), @id_params)
  144. resulting_state = @client.get_state(group_0_params)
  145. expect(resulting_state).to_not include('level')
  146. # white mode -> color.
  147. white_mode_desired_state = {'status' => 'ON', 'color_temp' => 253, 'level' => 11}
  148. @client.patch_state(white_mode_desired_state, group_0_params)
  149. @client.patch_state({'hue' => 10}, @id_params)
  150. resulting_state = @client.get_state(group_0_params)
  151. expect(resulting_state).to_not include('level')
  152. @client.patch_state({'hue' => 10}, group_0_params)
  153. resulting_state = @client.get_state(group_0_params)
  154. expect(resulting_state['level']).to eq(100)
  155. # white mode -> effect mode. level never set for group 0, so level should
  156. # level should be present.
  157. @client.patch_state(white_mode_desired_state, group_0_params)
  158. @client.patch_state({'mode' => 0}, @id_params)
  159. resulting_state = @client.get_state(group_0_params)
  160. expect(resulting_state).to_not include('level')
  161. # effect mode -> color. same as white mode -> color
  162. effect_mode_desired_state = {'status' => 'ON', 'mode' => 0, 'level' => 100}
  163. @client.patch_state(effect_mode_desired_state, group_0_params)
  164. @client.patch_state({'hue' => 10}, @id_params)
  165. resulting_state = @client.get_state(group_0_params)
  166. expect(resulting_state).to_not include('level')
  167. # effect mode -> white
  168. @client.patch_state(effect_mode_desired_state, group_0_params)
  169. @client.patch_state({'color_temp' => 253}, @id_params)
  170. resulting_state = @client.get_state(group_0_params)
  171. expect(resulting_state).to_not include('level')
  172. end
  173. end
  174. context 'fields' do
  175. it 'should support the color field' do
  176. desired_state = {
  177. 'hue' => 0,
  178. 'saturation' => 100,
  179. 'status' => 'ON'
  180. }
  181. @client.patch_state(
  182. desired_state.merge(hue: 100),
  183. @id_params
  184. )
  185. @client.patch_state(
  186. { color: '255,0,0' },
  187. @id_params
  188. )
  189. state = @client.get_state(@id_params)
  190. expect(state.keys).to include(*desired_state.keys)
  191. expect(state.select { |x| desired_state.include?(x) } ).to eq(desired_state)
  192. @client.patch_state(
  193. { color: {r: 0, g: 255, b: 0} },
  194. @id_params
  195. )
  196. state = @client.get_state(@id_params)
  197. desired_state.merge!('hue' => 120)
  198. expect(state.keys).to include(*desired_state.keys)
  199. expect(state.select { |x| desired_state.include?(x) } ).to eq(desired_state)
  200. end
  201. end
  202. context 'increment/decrement commands' do
  203. it 'should assume state after sufficiently many down commands' do
  204. id = @id_params.merge(type: 'cct')
  205. @client.delete_state(id)
  206. @client.patch_state({status: 'on'}, id)
  207. expect(@client.get_state(id)).to_not include('brightness', 'kelvin')
  208. 10.times do
  209. @client.patch_state(
  210. { commands: ['level_down', 'temperature_down'] },
  211. id
  212. )
  213. end
  214. state = @client.get_state(id)
  215. expect(state).to include('level', 'kelvin')
  216. expect(state['level']).to eq(0)
  217. expect(state['kelvin']).to eq(0)
  218. end
  219. it 'should assume state after sufficiently many up commands' do
  220. id = @id_params.merge(type: 'cct')
  221. @client.delete_state(id)
  222. @client.patch_state({status: 'on'}, id)
  223. expect(@client.get_state(id)).to_not include('level', 'kelvin')
  224. 10.times do
  225. @client.patch_state(
  226. { commands: ['level_up', 'temperature_up'] },
  227. id
  228. )
  229. end
  230. state = @client.get_state(id)
  231. expect(state).to include('level', 'kelvin')
  232. expect(state['level']).to eq(100)
  233. expect(state['kelvin']).to eq(100)
  234. end
  235. it 'should affect known state' do
  236. id = @id_params.merge(type: 'cct')
  237. @client.delete_state(id)
  238. @client.patch_state({status: 'on'}, id)
  239. expect(@client.get_state(id)).to_not include('level', 'kelvin')
  240. 10.times do
  241. @client.patch_state(
  242. { commands: ['level_up', 'temperature_up'] },
  243. id
  244. )
  245. end
  246. @client.patch_state(
  247. { commands: ['level_down', 'temperature_down'] },
  248. id
  249. )
  250. state = @client.get_state(id)
  251. expect(state).to include('level', 'kelvin')
  252. expect(state['level']).to eq(90)
  253. expect(state['kelvin']).to eq(90)
  254. end
  255. end
  256. end