transition_spec.rb 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. require 'api_client'
  2. RSpec.describe 'Transitions' do
  3. before(:all) do
  4. @client = ApiClient.from_environment
  5. @client.upload_json('/settings', 'settings.json')
  6. @transition_params = {
  7. field: 'level',
  8. start_value: 0,
  9. end_value: 100,
  10. duration: 2.0,
  11. period: 400
  12. }
  13. @num_transition_updates = (@transition_params[:duration]*1000)/@transition_params[:period]
  14. end
  15. before(:each) do
  16. mqtt_params = mqtt_parameters()
  17. @updates_topic = mqtt_params[:updates_topic]
  18. @topic_prefix = mqtt_topic_prefix()
  19. @client.put(
  20. '/settings',
  21. mqtt_params.merge(
  22. mqtt_update_topic_pattern: "#{@topic_prefix}updates/:device_id/:device_type/:group_id"
  23. )
  24. )
  25. @id_params = {
  26. id: @client.generate_id,
  27. type: 'rgb_cct',
  28. group_id: 1
  29. }
  30. @client.delete_state(@id_params)
  31. @mqtt_client = create_mqtt_client()
  32. # Delete any existing transitions
  33. @client.get('/transitions')['transitions'].each do |t|
  34. @client.delete("/transitions/#{t['id']}")
  35. end
  36. end
  37. context 'REST routes' do
  38. it 'should respond with an empty list when there are no transitions' do
  39. response = @client.transitions
  40. expect(response).to eq([])
  41. end
  42. it 'should respond with an error when missing parameters for POST /transitions' do
  43. expect { @client.post('/transitions', {}) }.to raise_error(Net::HTTPServerException)
  44. end
  45. it 'should create a new transition with a valid POST /transitions request' do
  46. response = @client.schedule_transition(@id_params, @transition_params)
  47. expect(response['success']).to eq(true)
  48. end
  49. it 'should list active transitions' do
  50. @client.schedule_transition(@id_params, @transition_params)
  51. response = @client.transitions
  52. expect(response.length).to be >= 1
  53. end
  54. it 'should support getting an active transition with GET /transitions/:id' do
  55. @client.schedule_transition(@id_params, @transition_params)
  56. response = @client.transitions
  57. detail_response = @client.get("/transitions/#{response.last['id']}")
  58. expect(detail_response['period']).to_not eq(nil)
  59. end
  60. it 'should support deleting active transitions with DELETE /transitions/:id' do
  61. @client.schedule_transition(@id_params, @transition_params)
  62. response = @client.transitions
  63. response.each do |transition|
  64. @client.delete("/transitions/#{transition['id']}")
  65. end
  66. after_delete_response = @client.transitions
  67. expect(response.length).to eq(1)
  68. expect(after_delete_response.length).to eq(0)
  69. end
  70. end
  71. context '"transition" key in state update' do
  72. it 'should create a new transition' do
  73. @client.patch_state({status: 'ON', level: 0}, @id_params)
  74. @client.patch_state({level: 100, transition: 2.0}, @id_params)
  75. response = @client.transitions
  76. expect(response.length).to be > 0
  77. expect(response.last['type']).to eq('field')
  78. expect(response.last['field']).to eq('level')
  79. expect(response.last['end_value']).to eq(100)
  80. @client.delete("/transitions/#{response.last['id']}")
  81. end
  82. it 'should transition field' do
  83. seen_updates = 0
  84. last_value = nil
  85. @client.patch_state({status: 'ON', level: 0}, @id_params)
  86. @mqtt_client.on_update(@id_params) do |id, msg|
  87. if msg.include?('brightness')
  88. seen_updates += 1
  89. last_value = msg['brightness']
  90. end
  91. last_value == 255
  92. end
  93. @client.patch_state({level: 100, transition: 2.0}, @id_params)
  94. @mqtt_client.wait_for_listeners
  95. expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000)
  96. expect(last_value).to eq(255)
  97. expect(seen_updates).to eq(expected_updates.length)
  98. end
  99. it 'should transition a field downwards' do
  100. seen_updates = 0
  101. last_value = nil
  102. @client.patch_state({status: 'ON'}, @id_params)
  103. @client.patch_state({level: 100}, @id_params)
  104. @mqtt_client.on_update(@id_params) do |id, msg|
  105. if msg.include?('brightness')
  106. seen_updates += 1
  107. last_value = msg['brightness']
  108. end
  109. last_value == 0
  110. end
  111. @client.patch_state({level: 0, transition: 2.0}, @id_params)
  112. @mqtt_client.wait_for_listeners
  113. expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000)
  114. expect(last_value).to eq(0)
  115. expect(seen_updates).to eq(expected_updates.length) # duration of 2000ms / 450ms period + 1 for initial packet
  116. end
  117. it 'should transition two fields at once if received in the same command' do
  118. updates = {}
  119. @client.patch_state({status: 'ON', hue: 0, level: 100}, @id_params)
  120. @mqtt_client.on_update(@id_params) do |id, msg|
  121. msg.each do |k, v|
  122. updates[k] ||= []
  123. updates[k] << v
  124. end
  125. updates['hue'] && updates['brightness'] && updates['hue'].last == 250 && updates['brightness'].last == 0
  126. end
  127. @client.patch_state({level: 0, hue: 250, transition: 2.0}, @id_params)
  128. @mqtt_client.wait_for_listeners
  129. expected_updates = calculate_transition_steps(start_value: 0, end_value: 250, duration: 2000)
  130. expect(updates['hue'].last).to eq(250)
  131. expect(updates['brightness'].last).to eq(0)
  132. expect(updates['hue'].length == updates['brightness'].length).to eq(true), "Should have the same number of updates for both fields"
  133. expect(updates['hue'].length).to eq(expected_updates.length)
  134. end
  135. it 'should support creating long transitions' do
  136. @client.patch_state({status: 'ON', level: 0}, @id_params)
  137. @client.patch_state({level: 100, transition: 60000}, @id_params)
  138. t = @client.transitions.last
  139. calculated_duration = t['period'] * (100.to_f / t['step_size'])
  140. expect(calculated_duration).to be_within(100).of(60000*1000), "Calculated duration should be close to 600s"
  141. end
  142. end
  143. context 'transition packets' do
  144. it 'should send an initial state packet' do
  145. seen = false
  146. @mqtt_client.on_update(@id_params) do |id, message|
  147. seen = message['brightness'] == 0
  148. end
  149. @client.schedule_transition(@id_params, @transition_params)
  150. @mqtt_client.wait_for_listeners
  151. expect(seen).to be(true)
  152. end
  153. it 'should respect the period parameter' do
  154. seen_updates = []
  155. start_time = Time.now
  156. @mqtt_client.on_update(@id_params) do |id, message|
  157. seen_updates << message
  158. message['brightness'] == 255
  159. end
  160. @client.schedule_transition(@id_params, @transition_params.merge(duration: 2.0, period: 500))
  161. @mqtt_client.wait_for_listeners
  162. expected_updates = calculate_transition_steps(start_value: 0, end_value: 255, period: 500, duration: 2000)
  163. transitions_are_equal(
  164. expected: expected_updates,
  165. seen: seen_updates.map { |x| x['brightness'] },
  166. # Allow some variation for the lossy level -> brightness conversion
  167. allowed_variation: 2
  168. )
  169. expect((Time.now - start_time)/4).to be >= 0.5 # Don't count the first update
  170. end
  171. it 'should support two transitions for different devices at the same time' do
  172. id1 = @id_params
  173. id2 = @id_params.merge(type: 'fut089')
  174. @client.schedule_transition(id1, @transition_params)
  175. @client.schedule_transition(id2, @transition_params)
  176. id1_updates = []
  177. id2_updates = []
  178. @mqtt_client.on_update do |id, msg|
  179. if id[:type] == id1[:type]
  180. id1_updates << msg
  181. else
  182. id2_updates << msg
  183. end
  184. id1_updates.length == @num_transition_updates && id2_updates.length == @num_transition_updates
  185. end
  186. @mqtt_client.wait_for_listeners
  187. expect(id1_updates.length).to eq(@num_transition_updates)
  188. expect(id2_updates.length).to eq(@num_transition_updates)
  189. end
  190. it 'should assume initial state if one is not provided' do
  191. @client.patch_state({status: 'ON', level: 0}, @id_params)
  192. seen_updates = []
  193. @mqtt_client.on_update(@id_params) do |id, message|
  194. seen_updates << message
  195. message['brightness'] == 255
  196. end
  197. @client.schedule_transition(@id_params, @transition_params.reject { |x| x == :start_value }.merge(duration: 2, period: 500))
  198. @mqtt_client.wait_for_listeners
  199. transitions_are_equal(
  200. expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000, period: 500),
  201. seen: seen_updates.map { |x| x['brightness'] },
  202. # Allow some variation for the lossy level -> brightness conversion
  203. allowed_variation: 2
  204. )
  205. end
  206. end
  207. context 'status transition' do
  208. it 'should turn off even if starting brightness is 0' do
  209. @client.patch_state({status: 'ON', brightness: 0}, @id_params)
  210. seen_off = false
  211. @mqtt_client.on_update(@id_params) do |id, message|
  212. seen_off = (message['state'] == 'OFF')
  213. end
  214. @client.patch_state({status: "OFF", transition: 1}, @id_params)
  215. @mqtt_client.wait_for_listeners
  216. expect(seen_off).to eq(true)
  217. end
  218. it 'should transition from off -> on' do
  219. seen_updates = {}
  220. @client.patch_state({status: 'OFF'}, @id_params)
  221. @mqtt_client.on_update(@id_params) do |id, message|
  222. message.each do |k, v|
  223. seen_updates[k] ||= []
  224. seen_updates[k] << v
  225. end
  226. seen_updates['brightness'] && seen_updates['brightness'].last == 255
  227. end
  228. @client.patch_state({status: 'ON', transition: 1.0}, @id_params)
  229. @mqtt_client.wait_for_listeners
  230. expect(seen_updates['state']).to eq(['ON'])
  231. transitions_are_equal(
  232. expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 1000),
  233. seen: seen_updates['brightness'],
  234. # Allow some variation for the lossy level -> brightness conversion
  235. allowed_variation: 3
  236. )
  237. end
  238. it 'should transition from on -> off' do
  239. seen_updates = {}
  240. @client.patch_state({status: 'ON', level: 100}, @id_params)
  241. @mqtt_client.on_update(@id_params) do |id, message|
  242. message.each do |k, v|
  243. seen_updates[k] ||= []
  244. seen_updates[k] << v
  245. end
  246. seen_updates['state'] == ['OFF']
  247. end
  248. @client.patch_state({status: 'OFF', transition: 1.0}, @id_params)
  249. @mqtt_client.wait_for_listeners
  250. expect(seen_updates['state']).to eq(['OFF'])
  251. transitions_are_equal(
  252. expected: calculate_transition_steps(start_value: 255, end_value: 0, duration: 1000),
  253. seen: seen_updates['brightness'],
  254. # Allow some variation for the lossy level -> brightness conversion
  255. allowed_variation: 3
  256. )
  257. end
  258. it 'should transition from off -> on from 0 to a provided brightness, even when there is a last known brightness' do
  259. seen_updates = {}
  260. @client.patch_state({status: 'ON', brightness: 99}, @id_params)
  261. @client.patch_state({status: 'OFF'}, @id_params)
  262. @mqtt_client.on_update(@id_params) do |id, message|
  263. message.each do |k, v|
  264. seen_updates[k] ||= []
  265. seen_updates[k] << v
  266. end
  267. seen_updates['brightness'] && seen_updates['brightness'].last == 128
  268. end
  269. @client.patch_state({status: 'ON', brightness: 128, transition: 1.0}, @id_params)
  270. @mqtt_client.wait_for_listeners
  271. transitions_are_equal(
  272. expected: calculate_transition_steps(start_value: 0, end_value: 128, duration: 1000),
  273. seen: seen_updates['brightness'],
  274. # Allow some variation for the lossy level -> brightness conversion
  275. allowed_variation: 4
  276. )
  277. end
  278. it 'should transition from off -> on from 0 to 100, even when there is a last known brightness if the bulb is off' do
  279. seen_updates = {}
  280. @client.patch_state({status: 'ON', brightness: 99}, @id_params)
  281. @client.patch_state({status: 'OFF'}, @id_params)
  282. @mqtt_client.on_update(@id_params) do |id, message|
  283. message.each do |k, v|
  284. seen_updates[k] ||= []
  285. seen_updates[k] << v
  286. end
  287. seen_updates['brightness'] && seen_updates['brightness'].last == 255
  288. end
  289. @mqtt_client.patch_state(@id_params, {state: 'ON', transition: 1.0})
  290. @mqtt_client.wait_for_listeners
  291. transitions_are_equal(
  292. expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 1000),
  293. seen: seen_updates['brightness'],
  294. # Allow some variation for the lossy level -> brightness conversion
  295. allowed_variation: 4
  296. )
  297. end
  298. it 'should transition from last known brightness if the bulb is already on' do
  299. seen_updates = {}
  300. @client.patch_state({status: 'ON', brightness: 99}, @id_params)
  301. @mqtt_client.on_update(@id_params) do |id, message|
  302. message.each do |k, v|
  303. seen_updates[k] ||= []
  304. seen_updates[k] << v
  305. end
  306. seen_updates['brightness'] && seen_updates['brightness'].last == 255
  307. end
  308. @mqtt_client.patch_state(@id_params, {state: 'ON', brightness: 255, transition: 1.0})
  309. @mqtt_client.wait_for_listeners
  310. transitions_are_equal(
  311. expected: calculate_transition_steps(start_value: 99, end_value: 255, duration: 1000),
  312. seen: seen_updates['brightness'],
  313. # Allow some variation for the lossy level -> brightness conversion
  314. allowed_variation: 4
  315. )
  316. end
  317. it 'should transition from on -> off with known last brightness' do
  318. seen_updates = {}
  319. @client.patch_state({status: 'ON', brightness: 99}, @id_params)
  320. @mqtt_client.on_update(@id_params) do |id, message|
  321. message.each do |k, v|
  322. seen_updates[k] ||= []
  323. seen_updates[k] << v
  324. end
  325. seen_updates['state'] == ['OFF']
  326. end
  327. @client.patch_state({status: 'OFF', transition: 1.0}, @id_params)
  328. @mqtt_client.wait_for_listeners
  329. transitions_are_equal(
  330. expected: calculate_transition_steps(start_value: 99, end_value: 0, duration: 1000),
  331. seen: seen_updates['brightness'],
  332. # Allow some variation for the lossy level -> brightness conversion
  333. allowed_variation: 3
  334. )
  335. end
  336. it 'should not transition to 100% if a brightness is specified' do
  337. seen_updates = {}
  338. # Set a last known level
  339. @client.patch_state({status: 'ON', level: 0}, @id_params)
  340. @client.patch_state({status: 'OFF'}, @id_params)
  341. @mqtt_client.on_update(@id_params) do |id, message|
  342. message.each do |k, v|
  343. seen_updates[k] ||= []
  344. seen_updates[k] << v
  345. end
  346. seen_updates['brightness'] && seen_updates['brightness'].last == 128
  347. end
  348. @client.patch_state({status: 'ON', brightness: 128, transition: 1.0}, @id_params)
  349. @mqtt_client.wait_for_listeners
  350. expect(seen_updates['state']).to eq(['ON'])
  351. transitions_are_equal(
  352. expected: calculate_transition_steps(start_value: 0, end_value: 128, duration: 1000),
  353. seen: seen_updates['brightness'],
  354. # Allow some variation for the lossy level -> brightness conversion
  355. allowed_variation: 3
  356. )
  357. end
  358. end
  359. context 'field support' do
  360. {
  361. 'level' => {range: [0, 100], update_field: 'brightness', update_max: 255},
  362. 'brightness' => {range: [0, 255]},
  363. 'kelvin' => {range: [0, 100], update_field: 'color_temp', update_min: 153, update_max: 370},
  364. 'color_temp' => {range: [153, 370]},
  365. 'hue' => {range: [0, 359]},
  366. 'saturation' => {range: [0, 100]}
  367. }.each do |field, params|
  368. min, max = params[:range]
  369. update_min = params[:update_min] || min
  370. update_max = params[:update_max] || max
  371. update_field = params[:update_field] || field
  372. it "should support field '#{field}' min --> max" do
  373. seen_updates = []
  374. @client.patch_state({'status' => 'ON', field => min}, @id_params)
  375. @mqtt_client.on_update(@id_params) do |id, message|
  376. seen_updates << message
  377. message[update_field] == update_max
  378. end
  379. @client.patch_state({field => max, 'transition' => 1.0}, @id_params)
  380. @mqtt_client.wait_for_listeners
  381. transitions_are_equal(
  382. expected: calculate_transition_steps(start_value: update_min, end_value: update_max, duration: 1000),
  383. seen: seen_updates.map{ |x| x[update_field] },
  384. allowed_variation: 3
  385. )
  386. end
  387. it "should support field '#{field}' max --> min" do
  388. seen_updates = []
  389. @client.patch_state({'status' => 'ON', field => max}, @id_params)
  390. @mqtt_client.on_update(@id_params) do |id, message|
  391. seen_updates << message
  392. message[update_field] == update_min
  393. end
  394. @client.patch_state({field => min, 'transition' => 1.0}, @id_params)
  395. @mqtt_client.wait_for_listeners
  396. transitions_are_equal(
  397. expected: calculate_transition_steps(start_value: update_max, end_value: update_min, duration: 1000),
  398. seen: seen_updates.map{ |x| x[update_field] },
  399. allowed_variation: 3
  400. )
  401. end
  402. end
  403. end
  404. context 'color support' do
  405. it 'should support color transitions' do
  406. response = @client.schedule_transition(@id_params, {
  407. field: 'color',
  408. start_value: '255,0,0',
  409. end_value: '0,255,0',
  410. duration: 1.0,
  411. period: 500
  412. })
  413. expect(response['success']).to eq(true)
  414. end
  415. it 'should smoothly transition from one color to another' do
  416. seen_updates = []
  417. end_color = '0,255,0'
  418. end_hs = rgb_to_hs(end_color)
  419. last_hue = nil
  420. last_sat = nil
  421. @mqtt_client.on_update(@id_params) do |id, message|
  422. field, value = message.first
  423. if field == 'hue'
  424. last_hue = value
  425. elsif field == 'saturation'
  426. last_sat = value
  427. end
  428. if !last_hue.nil? && !last_sat.nil?
  429. seen_updates << {hue: last_hue, saturation: last_sat}
  430. end
  431. last_hue == end_hs[:hue] && last_sat == end_hs[:saturation]
  432. end
  433. response = @client.schedule_transition(@id_params, {
  434. field: 'color',
  435. start_value: '255,0,0',
  436. end_value: '0,255,0',
  437. duration: 4.0,
  438. period: 1000
  439. })
  440. @mqtt_client.wait_for_listeners
  441. # This ends up being less even than you'd expect because RGB -> Hue/Sat is lossy.
  442. # Raw logs show that the right thing is happening:
  443. #
  444. # >>> stepSizes = (-64,64,0)
  445. # >>> start = (255,0,0)
  446. # >>> end = (0,255,0)
  447. # >>> current color = (191,64,0)
  448. # >>> current color = (127,128,0)
  449. # >>> current color = (63,192,0)
  450. # >>> current color = (0,255,0)
  451. expected_updates = calculate_color_transition_steps(start_color: '255,0,0', end_color: '0,255,0', duration: 4000, period: 1000)
  452. color_transitions_are_equal(
  453. expected: expected_updates,
  454. seen: seen_updates
  455. )
  456. end
  457. it 'should handle color transitions from known state' do
  458. seen_updates = []
  459. @client.patch_state({status: 'ON', color: '255,0,0'}, @id_params)
  460. end_color = '0,0,255'
  461. end_hs = rgb_to_hs(end_color)
  462. last_hue = nil
  463. last_sat = nil
  464. @mqtt_client.on_update(@id_params) do |id, message|
  465. field, value = message.first
  466. if field == 'hue'
  467. last_hue = value
  468. elsif field == 'saturation'
  469. last_sat = value
  470. end
  471. if !last_hue.nil? && !last_sat.nil?
  472. seen_updates << {hue: last_hue, saturation: last_sat}
  473. end
  474. last_hue == end_hs[:hue] && last_sat == end_hs[:saturation]
  475. end
  476. @client.patch_state({color: '0,0,255', transition: 2.0}, @id_params)
  477. @mqtt_client.wait_for_listeners
  478. expected_updates = calculate_color_transition_steps(start_color: '255,0,0', end_color: '0,0,255', duration: 2000)
  479. color_transitions_are_equal(
  480. expected: expected_updates,
  481. seen: seen_updates
  482. )
  483. end
  484. end
  485. context 'computed parameters' do
  486. (@transition_defaults = {
  487. duration: {default: 10.0, test: 2},
  488. period: {default: 500, test: 225}
  489. }).each do |k, params|
  490. it "it should compute other parameters given only #{k}" do
  491. seen_values = 0
  492. gap = 0
  493. @mqtt_client.on_update(@id_params) do |id, msg|
  494. val = msg['brightness']
  495. if val > 0
  496. seen_values += 1
  497. last_seen = val
  498. end
  499. if seen_values == 3
  500. gap = last_seen/seen_values
  501. end
  502. val == 255
  503. end
  504. t_params = {field: 'level', start_value: 0, end_value: 100}.merge({k => params[:test]})
  505. start_time = Time.now
  506. @client.schedule_transition(@id_params, t_params)
  507. transitions = @client.transitions
  508. @mqtt_client.wait_for_listeners
  509. duration = Time.now - start_time
  510. expect(transitions.length).to eq(1), "Should only be one active transition"
  511. period = transitions.first['period']
  512. expected_duration = (k == :duration ? params[:test] : (TransitionHelpers::Defaults::DURATION/1000.0))
  513. num_periods = (expected_duration/period.to_f)*1000
  514. expect(duration).to be_within(2).of(expected_duration)
  515. expect(gap).to be_within(10).of((255/num_periods).ceil)
  516. end
  517. end
  518. end
  519. context 'default parameters in settings' do
  520. it 'should respect the default parameter setting key' do
  521. [500, 1000, 2000].each do |period|
  522. field = 'brightness'
  523. @client.patch_settings(default_transition_period: period)
  524. @client.delete_state(@id_params)
  525. @client.patch_state({'status' => 'ON', field => 0}, @id_params)
  526. seen_updates = []
  527. @mqtt_client.on_update(@id_params) do |id, message|
  528. seen_updates << message[field] if !message[field].nil?
  529. seen_updates.last == 255
  530. end
  531. @client.patch_state({field => 255, 'transition' => 2.0, period: period}, @id_params)
  532. @mqtt_client.wait_for_listeners
  533. @mqtt_client = create_mqtt_client()
  534. transitions_are_equal(
  535. expected: calculate_transition_steps(start_value: 0, end_value: 255, duration: 2000, period: period),
  536. seen: seen_updates,
  537. allowed_variation: 3
  538. )
  539. end
  540. end
  541. it 'for upwards transition, should throttle frequency if step size does not allow for default period' do
  542. @client.patch_state({status: "ON", brightness: 0}, @id_params)
  543. @client.patch_state({brightness: 255, transition: 3600}, @id_params)
  544. transitions = @client.transitions
  545. expect(transitions.count).to eq(1)
  546. expect(transitions.first['period']).to eq((3600000/255.0).round)
  547. end
  548. it 'for downwards transition, should throttle frequency if step size does not allow for default period' do
  549. @client.patch_state({status: "ON", brightness: 255}, @id_params)
  550. @client.patch_state({brightness: 0, transition: 3600}, @id_params)
  551. transitions = @client.transitions
  552. expect(transitions.count).to eq(1)
  553. expect(transitions.first['period']).to eq((3600000/255.0).round)
  554. end
  555. end
  556. end