1import pytest 2from _testutils import MockHidapiDevice, Report, MockRuntimeStorage 3 4from liquidctl.driver.commander_pro import _quoted, _prepare_profile, _fan_mode_desc, CommanderPro 5from liquidctl.error import NotSupportedByDevice 6 7 8# hardcoded responce data expected for some of the calls: 9# commander pro: firmware request (0.9.214) 10# commander pro: bootloader req (2.3) 11# commander pro: get temp config ( 3 sensors) 12# commander pro: get fan configs (3 DC fans, 1 PWM fan) # note I have not tested it with pwm fans 13# commander pro: 14 15 16@pytest.fixture 17def commanderProDeviceUnconnected(): 18 device = MockHidapiDevice(vendor_id=0x1b1c, product_id=0x0c10, address='addr') 19 return CommanderPro(device, 'Corsair Commander Pro (experimental)', 6, 4, 2) 20 21 22@pytest.fixture 23def lightingNodeProDeviceUnconnected(): 24 device = MockHidapiDevice(vendor_id=0x1b1c, product_id=0x0c0b, address='addr') 25 return CommanderPro(device, 'Corsair Lighting Node Pro (experimental)', 0, 0, 2) 26 27 28@pytest.fixture 29def commanderProDevice(): 30 device = MockHidapiDevice(vendor_id=0x1b1c, product_id=0x0c10, address='addr') 31 pro = CommanderPro(device, 'Corsair Commander Pro (experimental)', 6, 4, 2) 32 33 34 runtime_storage = MockRuntimeStorage(key_prefixes=['testing']) 35 pro.connect(runtime_storage=runtime_storage) 36 return pro 37 38 39@pytest.fixture 40def lightingNodeProDevice(): 41 device = MockHidapiDevice(vendor_id=0x1b1c, product_id=0x0c0b, address='addr') 42 node = CommanderPro(device, 'Corsair Lighting Node Pro (experimental)', 0, 0, 2) 43 runtime_storage = MockRuntimeStorage(key_prefixes=['testing']) 44 node.connect(runtime_storage=runtime_storage) 45 return node 46 47@pytest.fixture 48def lightingNodeCoreDevice(): 49 device = MockHidapiDevice(vendor_id=0x1b1c, product_id=0x0c1a, address='addr') 50 node = CommanderPro(device, 'Corsair Lighting Node Core (experimental)', 0, 0, 1) 51 runtime_storage = MockRuntimeStorage(key_prefixes=['testing']) 52 node.connect(runtime_storage=runtime_storage) 53 return node 54 55 56 57# prepare profile 58def test_prepare_profile_valid_max_rpm(): 59 assert _prepare_profile([[10, 400], [20, 5000]], 60) == [(10, 400), (20, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 60 61 62def test_prepare_profile_add_max_rpm(): 63 assert _prepare_profile([[10, 400]], 60) == [(10, 400), (60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 64 assert _prepare_profile([[10, 400], [20, 500], [30, 600], [40, 700], [50, 800]], 60) == [(10, 400), (20, 500), (30, 600), (40, 700), (50, 800), (60, 5000)] 65 66 67def test_prepare_profile_missing_max_rpm(): 68 with pytest.raises(ValueError): 69 _prepare_profile([[10, 400], [20, 500], [30, 600], [40, 700], [50, 800], [55, 900]], 60) 70 71 72def test_prepare_profile_full_set(): 73 assert _prepare_profile([[10, 400], [20, 500], [30, 600], [40, 700], [45, 2000], [50, 5000]], 60) == [(10, 400), (20, 500), (30, 600), (40, 700), (45, 2000), (50, 5000)] 74 75 76def test_prepare_profile_too_many_points(): 77 with pytest.raises(ValueError): 78 _prepare_profile([[10, 400], [20, 500], [30, 600], [40, 700], [50, 800], [55, 900]], 60) 79 80 81def test_prepare_profile_no_points(): 82 assert _prepare_profile([], 60) == [(60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 83 84 85def test_prepare_profile_empty_list(): 86 assert _prepare_profile([], 60) == [(60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 87 88 89def test_prepare_profile_above_max_temp(): 90 assert _prepare_profile([[10, 400], [70, 2000]], 60) == [(10, 400), (60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 91 92 93def test_prepare_profile_temp_low(): 94 assert _prepare_profile([[-10, 400], [70, 2000]], 60) == [(-10, 400), (60, 5000), (60, 5000), (60, 5000), (60, 5000), (60, 5000)] 95 96 97def test_prepare_profile_max_temp(): 98 assert _prepare_profile([], 100) == [(100, 5000), (100, 5000), (100, 5000), (100, 5000), (100, 5000), (100, 5000)] 99 100 101# quoted 102def test_quoted_empty(): 103 assert _quoted() == '' 104 105 106def test_quoted_single(): 107 assert _quoted('one arg') == "'one arg'" 108 109 110def test_quoted_valid(): 111 assert _quoted('one', 'two') == "'one', 'two'" 112 113 114def test_quoted_not_string(): 115 assert _quoted('test', 500) == "'test', 500" 116 117 118# fan modes 119def test_get_fan_mode_description_auto(): 120 assert _fan_mode_desc(0x00) == None 121 122 123def test_get_fan_mode_description_unknown(): 124 assert _fan_mode_desc(0x03) == None 125 assert _fan_mode_desc(0x04) == None 126 assert _fan_mode_desc(0x10) == None 127 assert _fan_mode_desc(0xff) == None 128 129 130def test_get_fan_mode_description_dc(): 131 assert _fan_mode_desc(0x01) == 'DC' 132 133 134def test_get_fan_mode_description_pwm(): 135 assert _fan_mode_desc(0x02) == 'PWM' 136 137 138# class methods 139def test_commander_constructor(commanderProDeviceUnconnected): 140 141 assert commanderProDeviceUnconnected._data is None 142 assert commanderProDeviceUnconnected._fan_names == ['fan1', 'fan2', 'fan3', 'fan4', 'fan5', 'fan6'] 143 assert commanderProDeviceUnconnected._led_names == ['led1', 'led2'] 144 assert commanderProDeviceUnconnected._temp_probs == 4 145 assert commanderProDeviceUnconnected._fan_count == 6 146 147 148def test_lighting_constructor(lightingNodeProDeviceUnconnected): 149 assert lightingNodeProDeviceUnconnected._data is None 150 assert lightingNodeProDeviceUnconnected._fan_names == [] 151 assert lightingNodeProDeviceUnconnected._led_names == ['led1', 'led2'] 152 assert lightingNodeProDeviceUnconnected._temp_probs == 0 153 assert lightingNodeProDeviceUnconnected._fan_count == 0 154 155 156def test_connect_commander(commanderProDeviceUnconnected): 157 commanderProDeviceUnconnected.connect() 158 assert commanderProDeviceUnconnected._data is not None 159 160 161def test_connect_lighting(lightingNodeProDeviceUnconnected): 162 lightingNodeProDeviceUnconnected.connect() 163 assert lightingNodeProDeviceUnconnected._data is not None 164 165 166def test_initialize_commander_pro(commanderProDevice): 167 168 responses = [ 169 '000009d4000000000000000000000000', # firmware 170 '00000500000000000000000000000000', # bootloader 171 '00010100010000000000000000000000', # temp probes 172 '00010102000000000000000000000000' # fan probes 173 ] 174 for d in responses: 175 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(d))) 176 177 res = commanderProDevice.initialize() 178 179 assert len(res) == 12 180 assert res[0] == ('Firmware version', '0.9.212', '') 181 assert res[1] == ('Bootloader version', '0.5', '') 182 183 assert res[2] == ('Temperature probe 1', True, '') 184 assert res[3] == ('Temperature probe 2', True, '') 185 assert res[4] == ('Temperature probe 3', False, '') 186 assert res[5] == ('Temperature probe 4', True, '') 187 188 assert res[6] == ('Fan 1 control mode', 'DC', '') 189 assert res[7] == ('Fan 2 control mode', 'DC', '') 190 assert res[8] == ('Fan 3 control mode', 'PWM', '') 191 assert res[9] == ('Fan 4 control mode', None, '') 192 assert res[10] == ('Fan 5 control mode', None, '') 193 assert res[11] == ('Fan 6 control mode', None, '') 194 195 data = commanderProDevice._data.load('fan_modes', None) 196 assert data is not None 197 assert len(data) == 6 198 assert data[0] == 0x01 199 assert data[1] == 0x01 200 assert data[2] == 0x02 201 assert data[3] == 0x00 202 assert data[4] == 0x00 203 assert data[5] == 0x00 204 205 data = commanderProDevice._data.load('temp_sensors_connected', None) 206 assert data is not None 207 assert len(data) == 4 208 assert data[0] == 0x01 209 assert data[1] == 0x01 210 assert data[2] == 0x00 211 assert data[3] == 0x01 212 213 214def test_initialize_lighting_node(lightingNodeProDevice): 215 responses = [ 216 '000009d4000000000000000000000000', # firmware 217 '00000500000000000000000000000000' # bootloader 218 ] 219 for d in responses: 220 lightingNodeProDevice.device.preload_read(Report(0, bytes.fromhex(d))) 221 222 res = lightingNodeProDevice.initialize() 223 224 assert len(res) == 2 225 assert res[0][1] == '0.9.212' 226 assert res[1][1] == '0.5' 227 228 data = lightingNodeProDevice._data.load('fan_modes', None) 229 assert data is None 230 231 data = lightingNodeProDevice._data.load('temp_sensors_connected', None) 232 assert data is None 233 234 235def test_get_status_commander_pro(commanderProDevice): 236 237 responses = [ 238 '000a8300000000000000000000000000', # temp sensor 1 239 '000b6a00000000000000000000000000', # temp sensor 2 240 '000a0e00000000000000000000000000', # temp sensor 4 241 '0003ac00000000000000000000000000', # fan speed 1 242 '0003ab00000000000000000000000000', # fan speed 2 243 '0003db00000000000000000000000000', # fan speed 3 244 '002f2200000000000000000000000000', # get 12v 245 '00136500000000000000000000000000', # get 5v 246 '000d1f00000000000000000000000000', # get 3.3v 247 ] 248 for d in responses: 249 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(d))) 250 251 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x02, 0x00, 0x00, 0x00]) 252 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x00, 0x01]) 253 254 res = commanderProDevice.get_status() 255 print(res) 256 257 assert len(res) == 9 258 259 # temp probes 260 assert res[0] == ('Temperature 1', 26.91, '°C') 261 assert res[1] == ('Temperature 2', 29.22, '°C') 262 assert res[2] == ('Temperature 4', 25.74, '°C') 263 264 # fans rpm 265 assert res[3] == ('Fan 1 speed', 940, 'rpm') 266 assert res[4] == ('Fan 2 speed', 939, 'rpm') 267 assert res[5] == ('Fan 3 speed', 987, 'rpm') 268 269 # voltages 270 assert res[6] == ('+12V rail', 12.066, 'V') 271 assert res[7] == ('+5V rail', 4.965, 'V') 272 assert res[8] == ('+3.3V rail', 3.359, 'V') 273 274 # check the commands sent 275 sent = commanderProDevice.device.sent 276 assert len(sent) == 9 277 278 assert sent[0].data[0] == 0x11 279 assert sent[1].data[0] == 0x11 280 assert sent[2].data[0] == 0x11 281 282 assert sent[3].data[0] == 0x21 283 assert sent[4].data[0] == 0x21 284 assert sent[5].data[0] == 0x21 285 286 assert sent[6].data[0] == 0x12 287 assert sent[7].data[0] == 0x12 288 assert sent[8].data[0] == 0x12 289 290 291def test_get_status_lighting_pro(lightingNodeProDevice): 292 293 res = lightingNodeProDevice.get_status() 294 assert len(res) == 0 295 296 297def test_get_temp_valid_sensor_commander(commanderProDevice): 298 299 response = '000a8300000000000000000000000000' 300 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 301 302 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x01, 0x01]) 303 304 res = commanderProDevice._get_temp(1) 305 306 assert res == 26.91 307 308 # check the commands sent 309 sent = commanderProDevice.device.sent 310 assert len(sent) == 1 311 assert sent[0].data[0] == 0x11 312 assert sent[0].data[1] == 1 313 314 315def test_get_temp_invalid_sensor_low_commander(commanderProDevice): 316 response = '000a8300000000000000000000000000' 317 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 318 319 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x01, 0x01]) 320 321 with pytest.raises(ValueError): 322 commanderProDevice._get_temp(-1) 323 324 # check the commands sent 325 sent = commanderProDevice.device.sent 326 assert len(sent) == 0 327 328 329def test_get_temp_invalid_sensor_high_commander(commanderProDevice): 330 response = '000a8300000000000000000000000000' 331 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 332 333 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x01, 0x01]) 334 335 with pytest.raises(ValueError): 336 commanderProDevice._get_temp(4) 337 338 # check the commands sent 339 sent = commanderProDevice.device.sent 340 assert len(sent) == 0 341 342 343def test_get_temp_lighting(lightingNodeProDevice): 344 response = '000a8300000000000000000000000000' 345 lightingNodeProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 346 347 lightingNodeProDevice._data.store('temp_sensors_connected', [0x00, 0x00, 0x00, 0x00]) 348 349 with pytest.raises(ValueError): 350 lightingNodeProDevice._get_temp(2) 351 352 # check the commands sent 353 sent = lightingNodeProDevice.device.sent 354 assert len(sent) == 0 355 356 357def test_get_fan_rpm_valid_commander(commanderProDevice): 358 359 response = '0003ac00000000000000000000000000' 360 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 361 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x02, 0x00, 0x00, 0x00]) 362 363 res = commanderProDevice._get_fan_rpm(1) 364 assert res == 940 365 366 # check the commands sent 367 sent = commanderProDevice.device.sent 368 assert len(sent) == 1 369 assert sent[0].data[0] == 0x21 370 assert sent[0].data[1] == 1 371 372 373def test_get_fan_rpm_invalid_low_commander(commanderProDevice): 374 375 response = '0003ac00000000000000000000000000' 376 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 377 378 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x02, 0x00, 0x00, 0x00]) 379 380 with pytest.raises(ValueError): 381 commanderProDevice._get_fan_rpm(-1) 382 383 # check the commands sent 384 sent = commanderProDevice.device.sent 385 assert len(sent) == 0 386 387 388def test_get_fan_rpm_invalid_high_commander(commanderProDevice): 389 response = '0003ac00000000000000000000000000' 390 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 391 392 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x02, 0x00, 0x00, 0x00]) 393 394 with pytest.raises(ValueError): 395 commanderProDevice._get_fan_rpm(7) 396 397 # check the commands sent 398 sent = commanderProDevice.device.sent 399 assert len(sent) == 0 400 401 402def test_get_fan_rpm_lighting(lightingNodeProDevice): 403 response = '0003ac00000000000000000000000000' 404 lightingNodeProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 405 406 with pytest.raises(ValueError): 407 lightingNodeProDevice._get_fan_rpm(7) 408 409 # check the commands sent 410 sent = lightingNodeProDevice.device.sent 411 assert len(sent) == 0 412 413 414def test_get_hw_fan_channels_all(commanderProDevice): 415 416 res = commanderProDevice._get_hw_fan_channels('sync') 417 assert res == [0, 1, 2, 3, 4, 5] 418 419 420def test_get_hw_fan_channels_lowercase(commanderProDevice): 421 res = commanderProDevice._get_hw_fan_channels('fan2') 422 assert res == [1] 423 424 425@pytest.mark.parametrize('channel', [ 426 'fan23', 'fan7', 'fan0', 'fan', 'led', 'led1', 'bob' 427 ]) 428def test_get_hw_fan_channels_invalid(commanderProDevice, channel): 429 with pytest.raises(ValueError): 430 commanderProDevice._get_hw_fan_channels(channel) 431 432 433@pytest.mark.parametrize('channel,expected', [ 434 ('led1', [0]), ('led2', [1]), ('sync', [0, 1]) 435 ]) 436def test_get_hw_led_channel_valid(commanderProDevice, channel, expected): 437 res = commanderProDevice._get_hw_led_channels(channel) 438 assert res == expected 439 440 441@pytest.mark.parametrize('channel,expected', [('led', [0])]) 442def test_get_hw_led_channel_valid_node_core(lightingNodeCoreDevice, channel, 443 expected): 444 res = lightingNodeCoreDevice._get_hw_led_channels(channel) 445 assert res == expected 446 447 448@pytest.mark.parametrize('channel', [ 449 'led0', 'led3', 'led', 'fan', 'fan1', 'bob' 450 ]) 451def test_get_hw_led_channels_invalid(commanderProDevice, channel): 452 with pytest.raises(ValueError): 453 commanderProDevice._get_hw_led_channels(channel) 454 455 456def test_set_fixed_speed_low(commanderProDevice): 457 458 response = '00000000000000000000000000000000' 459 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 460 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) 461 462 commanderProDevice.set_fixed_speed('fan4', -10) 463 464 # check the commands sent 465 sent = commanderProDevice.device.sent 466 assert len(sent) == 1 467 468 assert sent[0].data[0] == 0x23 469 assert sent[0].data[1] == 0x03 470 assert sent[0].data[2] == 0x00 471 472 473def test_set_fixed_speed_high(commanderProDevice): 474 response = '00000000000000000000000000000000' 475 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 476 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) 477 478 commanderProDevice.set_fixed_speed('fan3', 110) 479 480 # check the commands sent 481 sent = commanderProDevice.device.sent 482 assert len(sent) == 1 483 484 assert sent[0].data[0] == 0x23 485 assert sent[0].data[1] == 0x02 486 assert sent[0].data[2] == 0x64 487 488 489def test_set_fixed_speed_valid(commanderProDevice): 490 491 response = '00000000000000000000000000000000' 492 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 493 commanderProDevice._data.store('fan_modes', [0x01, 0x01, 0x01, 0x01, 0x01, 0x01]) 494 495 commanderProDevice.set_fixed_speed('fan2', 50) 496 497 # check the commands sent 498 sent = commanderProDevice.device.sent 499 assert len(sent) == 1 500 501 assert sent[0].data[0] == 0x23 502 assert sent[0].data[1] == 0x01 503 assert sent[0].data[2] == 0x32 504 505 506def test_set_fixed_speed_valid_unconfigured(commanderProDevice): 507 508 response = '00000000000000000000000000000000' 509 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 510 commanderProDevice._data.store('fan_modes', [0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) 511 512 commanderProDevice.set_fixed_speed('fan2', 50) 513 514 # check the commands sent 515 sent = commanderProDevice.device.sent 516 assert len(sent) == 0 517 518 519def test_set_fixed_speed_valid_multi_fan(commanderProDevice): 520 responses = [ 521 '00000000000000000000000000000000', 522 '00000000000000000000000000000000', 523 '00000000000000000000000000000000', 524 '00000000000000000000000000000000', 525 '00000000000000000000000000000000' 526 ] 527 528 for d in responses: 529 commanderProDevice.device.preload_read(Report(0, bytes.fromhex(d))) 530 531 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 532 533 commanderProDevice.set_fixed_speed('sync', 50) 534 535 # check the commands sent 536 sent = commanderProDevice.device.sent 537 assert len(sent) == 3 538 539 assert sent[0].data[0] == 0x23 540 assert sent[0].data[1] == 0x00 541 assert sent[0].data[2] == 0x32 542 543 assert sent[1].data[0] == 0x23 544 assert sent[1].data[1] == 0x02 545 assert sent[1].data[2] == 0x32 546 547 assert sent[2].data[0] == 0x23 548 assert sent[2].data[1] == 0x03 549 assert sent[2].data[2] == 0x32 550 551 552def test_set_fixed_speed_lighting(lightingNodeProDevice): 553 response = '00000000000000000000000000000000' 554 lightingNodeProDevice.device.preload_read(Report(0, bytes.fromhex(response))) 555 556 with pytest.raises(NotSupportedByDevice): 557 lightingNodeProDevice.set_fixed_speed('sync', 50) 558 559 # check the commands sent 560 sent = lightingNodeProDevice.device.sent 561 assert len(sent) == 0 562 563 564def test_set_speed_profile_valid_multi_fan(commanderProDevice): 565 ignore = Report(0, bytes(16)) 566 for _ in range(5): 567 commanderProDevice.device.preload_read(ignore) 568 569 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x00, 0x01]) 570 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 571 commanderProDevice.set_speed_profile('sync', [(10, 500), (20, 1000)]) 572 573 # check the commands sent 574 sent = commanderProDevice.device.sent 575 assert len(sent) == 3 576 577 assert sent[0].data[0] == 0x25 578 assert sent[0].data[1] == 0x00 579 assert sent[0].data[2] == 0x00 580 581 assert sent[0].data[3] == 0x03 582 assert sent[0].data[4] == 0xe8 583 assert sent[0].data[15] == 0x01 584 assert sent[0].data[16] == 0xf4 585 586 assert sent[1].data[0] == 0x25 587 assert sent[1].data[1] == 0x02 588 assert sent[1].data[2] == 0x00 589 590 assert sent[2].data[0] == 0x25 591 assert sent[2].data[1] == 0x03 592 assert sent[2].data[2] == 0x00 593 594 595def test_set_speed_profile_invalid_temp_sensor(commanderProDevice): 596 ignore = Report(0, bytes(16)) 597 for _ in range(5): 598 commanderProDevice.device.preload_read(ignore) 599 600 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x00, 0x01]) 601 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 602 603 commanderProDevice.set_speed_profile('fan1', [(10, 500), (20, 1000)], temperature_sensor=10) 604 605 # check the commands sent 606 sent = commanderProDevice.device.sent 607 assert len(sent) == 1 608 609 assert sent[0].data[0] == 0x25 610 assert sent[0].data[1] == 0x00 611 assert sent[0].data[2] == 0x03 612 613 assert sent[0].data[3] == 0x03 614 assert sent[0].data[4] == 0xe8 615 assert sent[0].data[15] == 0x01 616 assert sent[0].data[16] == 0xf4 617 618 619def test_set_speed_profile_no_temp_sensors(commanderProDevice): 620 ignore = Report(0, bytes(16)) 621 for _ in range(5): 622 commanderProDevice.device.preload_read(ignore) 623 624 commanderProDevice._data.store('temp_sensors_connected', [0x00, 0x00, 0x00, 0x00]) 625 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 626 627 with pytest.raises(ValueError): 628 commanderProDevice.set_speed_profile('sync', [(10, 500), (20, 1000)], temperature_sensor=1) 629 630 # check the commands sent 631 sent = commanderProDevice.device.sent 632 assert len(sent) == 0 633 634 635def test_set_speed_profile_valid(commanderProDevice): 636 ignore = Report(0, bytes(16)) 637 for _ in range(5): 638 commanderProDevice.device.preload_read(ignore) 639 640 commanderProDevice._data.store('temp_sensors_connected', [0x01, 0x01, 0x00, 0x01]) 641 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 642 commanderProDevice.set_speed_profile('fan3', [(10, 500), (20, 1000)]) 643 644 # check the commands sent 645 sent = commanderProDevice.device.sent 646 assert len(sent) == 1 647 648 assert sent[0].data[0] == 0x25 649 assert sent[0].data[1] == 0x02 650 assert sent[0].data[2] == 0x00 651 652 assert sent[0].data[3] == 0x03 653 assert sent[0].data[4] == 0xe8 654 assert sent[0].data[15] == 0x01 655 assert sent[0].data[16] == 0xf4 656 657 658def test_set_speed_profile_node(lightingNodeProDevice): 659 ignore = Report(0, bytes(16)) 660 for _ in range(5): 661 lightingNodeProDevice.device.preload_read(ignore) 662 663 lightingNodeProDevice._data.store('temp_sensors_connected', [0x01, 0x00, 0x00, 0x00]) 664 lightingNodeProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 665 666 with pytest.raises(NotSupportedByDevice): 667 lightingNodeProDevice.set_speed_profile('sync', [(10, 500), (20, 1000)]) 668 669 # check the commands sent 670 sent = lightingNodeProDevice.device.sent 671 assert len(sent) == 0 672 673 674def test_set_speed_profile_core(lightingNodeCoreDevice): 675 ignore = Report(0, bytes(16)) 676 for _ in range(5): 677 lightingNodeCoreDevice.device.preload_read(ignore) 678 679 lightingNodeCoreDevice._data.store('temp_sensors_connected', [0x01, 0x00, 0x00, 0x00]) 680 lightingNodeCoreDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 681 682 with pytest.raises(NotSupportedByDevice): 683 lightingNodeCoreDevice.set_speed_profile('sync', [(10, 500), (20, 1000)]) 684 685 # check the commands sent 686 sent = lightingNodeCoreDevice.device.sent 687 assert len(sent) == 0 688 689 690def test_set_speed_profile_valid_unconfigured(commanderProDevice): 691 ignore = Report(0, bytes(16)) 692 for _ in range(5): 693 commanderProDevice.device.preload_read(ignore) 694 695 commanderProDevice._data.store('temp_sensors_connected', [0x00, 0x00, 0x00, 0x00]) 696 commanderProDevice._data.store('fan_modes', [0x01, 0x00, 0x01, 0x01, 0x00, 0x00]) 697 698 with pytest.raises(ValueError): 699 commanderProDevice.set_speed_profile('fan2', [(10, 500), (20, 1000)]) 700 701 # check the commands sent 702 sent = commanderProDevice.device.sent 703 assert len(sent) == 0 704 705 706def test_set_color_hardware_clear(commanderProDevice): 707 ignore = Report(0, bytes(16)) 708 for _ in range(6): 709 commanderProDevice.device.preload_read(ignore) 710 711 effect = { 712 'channel': 0x01, 713 'start_led': 0x00, 714 'num_leds': 0x0f, 715 'mode': 0x0a, 716 'speed': 0x00, 717 'direction': 0x00, 718 'random_colors': 0x00, 719 'colors': [] 720 } 721 commanderProDevice._data.store('saved_effects', [effect]) 722 723 commanderProDevice.set_color('led1', 'clear', [], ) 724 725 # check the commands sent 726 sent = commanderProDevice.device.sent 727 assert len(sent) == 0 728 729 effects = commanderProDevice._data.load('saved_effects', default=None) 730 731 assert effects is None 732 733 734def test_set_color_hardware_off(commanderProDevice): 735 ignore = Report(0, bytes(16)) 736 for _ in range(6): 737 commanderProDevice.device.preload_read(ignore) 738 739 effect = { 740 'channel': 0x01, 741 'start_led': 0x00, 742 'num_leds': 0x0f, 743 'mode': 0x0a, 744 'speed': 0x00, 745 'direction': 0x00, 746 'random_colors': 0x00, 747 'colors': [] 748 } 749 commanderProDevice._data.store('saved_effects', [effect]) 750 751 commanderProDevice.set_color('led1', 'off', []) 752 753 # check the commands sent 754 sent = commanderProDevice.device.sent 755 assert len(sent) == 5 756 757 assert sent[3].data[0] == 0x35 758 assert sent[3].data[4] == 0x04 759 760 effects = commanderProDevice._data.load('saved_effects', default=None) 761 762 assert effects is None 763 764 765@pytest.mark.parametrize('directionStr,expected', 766 [('forward', 0x01), ('backward', 0x00)]) 767def test_set_color_hardware_direction(commanderProDevice, directionStr, expected): 768 ignore = Report(0, bytes(16)) 769 for _ in range(6): 770 commanderProDevice.device.preload_read(ignore) 771 772 colors = [[0xaa, 0xbb, 0xcc]] 773 commanderProDevice.set_color('led1', 'fixed', colors, direction=directionStr) 774 775 # check the commands sent 776 sent = commanderProDevice.device.sent 777 assert len(sent) == 5 778 779 assert sent[3].data[0] == 0x35 780 assert sent[3].data[6] == expected 781 782 effects = commanderProDevice._data.load('saved_effects', default=None) 783 784 assert effects is not None 785 assert len(effects) == 1 786 787 788def test_set_color_hardware_direction_default(commanderProDevice): 789 ignore = Report(0, bytes(16)) 790 for _ in range(6): 791 commanderProDevice.device.preload_read(ignore) 792 793 colors = [[0xaa, 0xbb, 0xcc]] 794 commanderProDevice.set_color('led1', 'fixed', colors) 795 796 # check the commands sent 797 sent = commanderProDevice.device.sent 798 assert len(sent) == 5 799 800 assert sent[3].data[0] == 0x35 801 assert sent[3].data[6] == 0x01 802 803 effects = commanderProDevice._data.load('saved_effects', default=None) 804 805 assert effects is not None 806 assert len(effects) == 1 807 808 809def test_set_color_hardware_speed_default(commanderProDevice): 810 ignore = Report(0, bytes(16)) 811 for _ in range(6): 812 commanderProDevice.device.preload_read(ignore) 813 814 colors = [[0xaa, 0xbb, 0xcc]] 815 commanderProDevice.set_color('led1', 'fixed', colors) 816 817 # check the commands sent 818 sent = commanderProDevice.device.sent 819 assert len(sent) == 5 820 821 assert sent[3].data[0] == 0x35 822 assert sent[3].data[5] == 0x01 823 824 effects = commanderProDevice._data.load('saved_effects', default=None) 825 826 assert effects is not None 827 assert len(effects) == 1 828 829 830@pytest.mark.parametrize('speedStr,expected', 831 [('slow', 0x02), ('fast', 0x00), ('medium', 0x01)]) 832def test_set_color_hardware_speed(commanderProDevice, speedStr, expected): 833 ignore = Report(0, bytes(16)) 834 for _ in range(6): 835 commanderProDevice.device.preload_read(ignore) 836 837 colors = [[0xaa, 0xbb, 0xcc]] 838 commanderProDevice.set_color('led1', 'fixed', colors, speed=speedStr) 839 840 # check the commands sent 841 sent = commanderProDevice.device.sent 842 assert len(sent) == 5 843 844 assert sent[3].data[0] == 0x35 845 assert sent[3].data[5] == expected 846 847 effects = commanderProDevice._data.load('saved_effects', default=None) 848 849 assert effects is not None 850 assert len(effects) == 1 851 852 853def test_set_color_hardware_default_start_end(commanderProDevice): 854 ignore = Report(0, bytes(16)) 855 for _ in range(6): 856 commanderProDevice.device.preload_read(ignore) 857 858 colors = [[0xaa, 0xbb, 0xcc]] 859 commanderProDevice.set_color('led1', 'fixed', colors) 860 861 # check the commands sent 862 sent = commanderProDevice.device.sent 863 assert len(sent) == 5 864 865 assert sent[3].data[0] == 0x35 866 assert sent[3].data[2] == 0 # start led 867 assert sent[3].data[3] == 204 # num leds 868 869 effects = commanderProDevice._data.load('saved_effects', default=None) 870 871 assert effects is not None 872 assert len(effects) == 1 873 874 875@pytest.mark.parametrize('startLED,expected', [ 876 (1, 0x00), (30, 0x1d), (92, 0x5b) 877 ]) 878def test_set_color_hardware_start_set(commanderProDevice, startLED, expected): 879 ignore = Report(0, bytes(16)) 880 for _ in range(6): 881 commanderProDevice.device.preload_read(ignore) 882 883 colors = [[0xaa, 0xbb, 0xcc]] 884 commanderProDevice.set_color('led1', 'fixed', colors, start_led=startLED) 885 886 # check the commands sent 887 sent = commanderProDevice.device.sent 888 assert len(sent) == 5 889 890 assert sent[3].data[0] == 0x35 891 assert sent[3].data[2] == expected # start led 892 893 effects = commanderProDevice._data.load('saved_effects', default=None) 894 895 assert effects is not None 896 assert len(effects) == 1 897 898 899@pytest.mark.parametrize('numLED,expected', [ 900 (1, 1), (30, 30), (96, 96), (203, 203), (204, 204), (205, 204) ]) 901def test_set_color_hardware_num_leds(commanderProDevice, numLED, expected): 902 ignore = Report(0, bytes(16)) 903 for _ in range(6): 904 commanderProDevice.device.preload_read(ignore) 905 906 colors = [[0xaa, 0xbb, 0xcc]] 907 commanderProDevice.set_color('led1', 'fixed', colors, start_led=1, maximum_leds=numLED) 908 909 # check the commands sent 910 sent = commanderProDevice.device.sent 911 assert len(sent) == 5 912 913 assert sent[3].data[0] == 0x35 914 assert sent[3].data[3] == expected # num leds 915 916 effects = commanderProDevice._data.load('saved_effects', default=None) 917 918 assert effects is not None 919 assert len(effects) == 1 920 921def test_set_color_hardware_too_many_leds(commanderProDevice): 922 ignore = Report(0, bytes(16)) 923 for _ in range(6): 924 commanderProDevice.device.preload_read(ignore) 925 926 colors = [[0xaa, 0xbb, 0xcc]] 927 commanderProDevice.set_color('led1', 'fixed', colors, start_led=200, maximum_leds=50) 928 929 # check the commands sent 930 sent = commanderProDevice.device.sent 931 assert len(sent) == 5 932 933 assert sent[3].data[0] == 0x35 934 assert sent[3].data[2] == 0xc7 # start led 935 assert sent[3].data[3] == 5 # num led 936 937 effects = commanderProDevice._data.load('saved_effects', default=None) 938 939 assert effects is not None 940 assert len(effects) == 1 941 942 943def test_set_color_hardware_too_few_leds(commanderProDevice): 944 ignore = Report(0, bytes(16)) 945 for _ in range(6): 946 commanderProDevice.device.preload_read(ignore) 947 948 colors = [[0xaa, 0xbb, 0xcc]] 949 commanderProDevice.set_color('led1', 'fixed', colors, start_led=1, maximum_leds=0) 950 951 # check the commands sent 952 sent = commanderProDevice.device.sent 953 assert len(sent) == 5 954 955 assert sent[3].data[0] == 0x35 956 assert sent[3].data[2] == 0x00 # start led 957 assert sent[3].data[3] == 0x01 # num led 958 959 effects = commanderProDevice._data.load('saved_effects', default=None) 960 961 assert effects is not None 962 assert len(effects) == 1 963 964 965@pytest.mark.parametrize('channel,expected', 966 [('led1', 0x00), ('led2', 0x01)]) 967def test_set_color_hardware_channel(commanderProDevice, channel, expected): 968 ignore = Report(0, bytes(16)) 969 for _ in range(6): 970 commanderProDevice.device.preload_read(ignore) 971 972 colors = [[0xaa, 0xbb, 0xcc]] 973 commanderProDevice.set_color(channel, 'fixed', colors) 974 975 # check the commands sent 976 sent = commanderProDevice.device.sent 977 assert len(sent) == 5 978 979 assert sent[0].data[1] == expected 980 assert sent[1].data[1] == expected 981 assert sent[2].data[1] == expected 982 assert sent[3].data[0] == 0x35 983 assert sent[3].data[1] == expected 984 985 effects = commanderProDevice._data.load('saved_effects', default=None) 986 987 assert effects is not None 988 assert len(effects) == 1 989 990 991def test_set_color_hardware_sync_channel(commanderProDevice): 992 ignore = Report(0, bytes(16)) 993 for _ in range(9): 994 commanderProDevice.device.preload_read(ignore) 995 996 colors = [[0xaa, 0xbb, 0xcc]] 997 commanderProDevice.set_color('sync', 'fixed', colors) 998 999 # check the commands sent 1000 sent = commanderProDevice.device.sent 1001 assert len(sent) == 2*(3 + 1) + 1 1002 1003 assert sent[0].data[1] == 0 1004 assert sent[1].data[1] == 0 1005 assert sent[2].data[1] == 0 1006 1007 assert sent[3].data[1] == 1 1008 assert sent[4].data[1] == 1 1009 assert sent[5].data[1] == 1 1010 1011 assert sent[6].data[0] == 0x35 1012 assert sent[6].data[1] == 0 1013 1014 assert sent[7].data[0] == 0x35 1015 assert sent[7].data[1] == 1 1016 1017 effects = commanderProDevice._data.load('saved_effects', default=None) 1018 1019 assert effects is not None 1020 assert len(effects) == 2 1021 1022 1023def test_set_color_hardware_random_color(commanderProDevice): 1024 ignore = Report(0, bytes(16)) 1025 for _ in range(6): 1026 commanderProDevice.device.preload_read(ignore) 1027 1028 colors = [] 1029 commanderProDevice.set_color('led1', 'fixed', colors) 1030 1031 # check the commands sent 1032 sent = commanderProDevice.device.sent 1033 assert len(sent) == 5 1034 1035 assert sent[3].data[0] == 0x35 1036 assert sent[3].data[7] == 0x01 1037 1038 effects = commanderProDevice._data.load('saved_effects', default=None) 1039 1040 assert effects is not None 1041 assert len(effects) == 1 1042 1043 1044def test_set_color_hardware_not_random_color(commanderProDevice): 1045 ignore = Report(0, bytes(16)) 1046 for _ in range(6): 1047 commanderProDevice.device.preload_read(ignore) 1048 1049 colors = [[0xaa, 0xbb, 0xcc]] 1050 commanderProDevice.set_color('led1', 'fixed', colors) 1051 1052 # check the commands sent 1053 sent = commanderProDevice.device.sent 1054 assert len(sent) == 5 1055 1056 assert sent[3].data[0] == 0x35 1057 assert sent[3].data[7] == 0x00 1058 1059 effects = commanderProDevice._data.load('saved_effects', default=None) 1060 1061 assert effects is not None 1062 assert len(effects) == 1 1063 1064 1065def test_set_color_hardware_too_many_colors(commanderProDevice): 1066 ignore = Report(0, bytes(16)) 1067 for _ in range(6): 1068 commanderProDevice.device.preload_read(ignore) 1069 1070 colors = [[0xaa, 0xbb, 0xcc], [0x00, 0x11, 0x22], [0x33, 0x44, 0x55]] 1071 commanderProDevice.set_color('led1', 'fixed', colors) 1072 1073 # check the commands sent 1074 sent = commanderProDevice.device.sent 1075 assert len(sent) == 5 1076 1077 assert sent[3].data[0] == 0x35 1078 assert sent[3].data[7] == 0x00 1079 1080 assert sent[3].data[9] == 0xaa 1081 assert sent[3].data[10] == 0xbb 1082 assert sent[3].data[11] == 0xcc 1083 1084 effects = commanderProDevice._data.load('saved_effects', default=None) 1085 1086 assert effects is not None 1087 assert len(effects) == 1 1088 1089 1090def test_set_color_hardware_too_few_colors(commanderProDevice): 1091 ignore = Report(0, bytes(16)) 1092 for _ in range(6): 1093 commanderProDevice.device.preload_read(ignore) 1094 1095 commanderProDevice.set_color('led1', 'fixed', []) 1096 1097 # check the commands sent 1098 sent = commanderProDevice.device.sent 1099 assert len(sent) == 5 1100 1101 assert sent[3].data[0] == 0x35 1102 assert sent[3].data[7] == 0x01 1103 1104 assert sent[3].data[9] == 0x00 1105 assert sent[3].data[10] == 0x00 1106 assert sent[3].data[11] == 0x00 1107 1108 effects = commanderProDevice._data.load('saved_effects', default=None) 1109 1110 assert effects is not None 1111 assert len(effects) == 1 1112 1113 1114@pytest.mark.parametrize('modeStr,expected', [ 1115 ('rainbow', 0x00), ('color_shift', 0x01), ('color_pulse', 0x02), 1116 ('color_wave', 0x03), ('fixed', 0x04), ('visor', 0x06), ('marquee', 0x07), 1117 ('blink', 0x08), ('sequential', 0x09), ('rainbow2', 0x0a), 1118 ]) 1119def test_set_color_hardware_valid_mode(commanderProDevice, modeStr, expected): 1120 ignore = Report(0, bytes(16)) 1121 for _ in range(6): 1122 commanderProDevice.device.preload_read(ignore) 1123 1124 commanderProDevice.set_color('led1', modeStr, []) 1125 1126 # check the commands sent 1127 sent = commanderProDevice.device.sent 1128 assert len(sent) == 5 1129 1130 assert sent[3].data[0] == 0x35 1131 assert sent[3].data[4] == expected 1132 1133 effects = commanderProDevice._data.load('saved_effects', default=None) 1134 1135 assert effects is not None 1136 assert len(effects) == 1 1137 1138 1139def test_set_color_hardware_invalid_mode(commanderProDevice): 1140 ignore = Report(0, bytes(16)) 1141 for _ in range(6): 1142 commanderProDevice.device.preload_read(ignore) 1143 1144 colors = [[0xaa, 0xbb, 0xcc]] 1145 1146 with pytest.raises(ValueError): 1147 commanderProDevice.set_color('led1', 'invalid', colors) 1148 1149 # check the commands sent 1150 sent = commanderProDevice.device.sent 1151 assert len(sent) == 0 1152 1153 effects = commanderProDevice._data.load('saved_effects', default=None) 1154 assert effects is None 1155 1156 1157def test_set_color_hardware_multipe_commands(commanderProDevice): 1158 ignore = Report(0, bytes(16)) 1159 for _ in range(6): 1160 commanderProDevice.device.preload_read(ignore) 1161 1162 effect = { 1163 'channel': 0x01, 1164 'start_led': 0x00, 1165 'num_leds': 0x0f, 1166 'mode': 0x0a, 1167 'speed': 0x00, 1168 'direction': 0x00, 1169 'random_colors': 0x00, 1170 'colors': [0xaa, 0xbb, 0xcc] 1171 } 1172 commanderProDevice._data.store('saved_effects', [effect]) 1173 1174 commanderProDevice.set_color('led1', 'fixed', [[0x00, 0x11, 0x22]], start_led=16, maximum_leds=5) 1175 1176 # check the commands sent 1177 sent = commanderProDevice.device.sent 1178 assert len(sent) == 6 1179 1180 assert sent[3].data[0] == 0x35 1181 assert sent[4].data[0] == 0x35 1182 1183 effects = commanderProDevice._data.load('saved_effects', default=None) 1184 1185 assert effects is not None 1186 assert len(effects) == 2 1187 1188 1189def test_set_color_hardware_last_commands(commanderProDevice): 1190 1191 for i in range(15): 1192 commanderProDevice.device.preload_read(Report(0, bytes.fromhex('00000000000000000000000000000000'))) 1193 1194 effect = { 1195 'channel': 0x01, 1196 'start_led': 0x00, 1197 'num_leds': 0x0f, 1198 'mode': 0x0a, 1199 'speed': 0x00, 1200 'direction': 0x00, 1201 'random_colors': 0x00, 1202 'colors': [0xaa, 0xbb, 0xcc] 1203 } 1204 commanderProDevice._data.store('saved_effects', [effect, effect, effect, effect, effect, effect, effect]) 1205 1206 commanderProDevice.set_color('led1', 'fixed', [[0x00, 0x11, 0x22]], start_led=16, maximum_leds=5) 1207 1208 # check the commands sent 1209 sent = commanderProDevice.device.sent 1210 assert len(sent) == 12 1211 1212 effects = commanderProDevice._data.load('saved_effects', default=None) 1213 1214 assert effects is not None 1215 assert len(effects) == 8 1216 1217 1218 1219def test_set_color_hardware_max_commands(commanderProDevice): 1220 1221 for i in range(15): 1222 commanderProDevice.device.preload_read(Report(0, bytes.fromhex('00000000000000000000000000000000'))) 1223 1224 effect = { 1225 'channel': 0x01, 1226 'start_led': 0x00, 1227 'num_leds': 0x0f, 1228 'mode': 0x0a, 1229 'speed': 0x00, 1230 'direction': 0x00, 1231 'random_colors': 0x00, 1232 'colors': [0xaa, 0xbb, 0xcc] 1233 } 1234 commanderProDevice._data.store('saved_effects', [effect, effect, effect, effect, effect, effect, effect, effect]) 1235 1236 commanderProDevice.set_color('led1', 'fixed', [[0x00, 0x11, 0x22]], start_led=16, maximum_leds=5) 1237 1238 # check the commands sent 1239 sent = commanderProDevice.device.sent 1240 assert len(sent) == 0 1241 1242 effects = commanderProDevice._data.load('saved_effects', default=None) 1243 1244 assert effects is not None 1245 assert len(effects) == 8 1246 1247 1248def test_set_color_hardware_too_many_commands(commanderProDevice): 1249 ignore = Report(0, bytes(16)) 1250 for _ in range(6): 1251 commanderProDevice.device.preload_read(ignore) 1252 1253 effect = { 1254 'channel': 0x01, 1255 'start_led': 0x00, 1256 'num_leds': 0x0f, 1257 'mode': 0x0a, 1258 'speed': 0x00, 1259 'direction': 0x00, 1260 'random_colors': 0x00, 1261 'colors': [0xaa, 0xbb, 0xcc] 1262 } 1263 commanderProDevice._data.store('saved_effects', [effect, effect, effect, effect, effect, effect, effect, effect, effect]) 1264 1265 commanderProDevice.set_color('led1', 'fixed', [[0x00, 0x11, 0x22]], start_led=16, maximum_leds=5) 1266 1267 # check the commands sent 1268 sent = commanderProDevice.device.sent 1269 assert len(sent) == 0 1270 1271 1272def test_send_command_valid_data(commanderProDevice): 1273 ignore = Report(0, bytes(16)) 1274 for _ in range(2): 1275 commanderProDevice.device.preload_read(ignore) 1276 1277 commanderProDevice._send_command(6, [255, 0, 20, 10, 15]) 1278 1279 # check the commands sent 1280 sent = commanderProDevice.device.sent 1281 assert len(sent) == 1 1282 assert len(sent[0].data) == 64 1283 assert sent[0].data[0] == 6 1284 assert sent[0].data[1] == 255 1285 1286 1287def test_send_command_no_data(commanderProDevice): 1288 ignore = Report(0, bytes(16)) 1289 for _ in range(2): 1290 commanderProDevice.device.preload_read(ignore) 1291 1292 commanderProDevice._send_command(6) 1293 1294 # check the commands sent 1295 sent = commanderProDevice.device.sent 1296 assert len(sent) == 1 1297 assert len(sent[0].data) == 64 1298 assert sent[0].data[0] == 6 1299 assert sent[0].data[1] == 0 1300 1301 1302def test_send_command_data_too_long(commanderProDevice): 1303 ignore = Report(0, bytes(16)) 1304 for _ in range(2): 1305 commanderProDevice.device.preload_read(ignore) 1306 1307 data = bytearray(100) 1308 commanderProDevice._send_command(3, data) 1309 1310 # check the commands sent 1311 sent = commanderProDevice.device.sent 1312 assert len(sent) == 1 1313 assert len(sent[0].data) == 64 1314 assert sent[0].data[0] == 3 1315 assert sent[0].data[1] == 0 1316