state_spec.rb 9.6 KB

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