Passed
Push — master ( 81bc91...434333 )
by Chris
03:03
created

MessageDecoder::decodeSetWaveform()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 2
dl 0
loc 14
ccs 0
cts 9
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\LibLifxLan\Decoding;
4
5
use DaveRandom\LibLifxLan\DataTypes as DeviceDataTypes;
6
use DaveRandom\LibLifxLan\DataTypes\Light as LightDataTypes;
7
use DaveRandom\LibLifxLan\Decoding\Exceptions\DecodingException;
8
use DaveRandom\LibLifxLan\Decoding\Exceptions\InvalidMessagePayloadLengthException;
9
use DaveRandom\LibLifxLan\Messages\Device\Commands as DeviceCommands;
10
use DaveRandom\LibLifxLan\Messages\Device\Requests as DeviceRequests;
11
use DaveRandom\LibLifxLan\Messages\Device\Responses as DeviceResponses;
12
use DaveRandom\LibLifxLan\Messages\Light\Commands as LightCommmands;
13
use DaveRandom\LibLifxLan\Messages\Light\Requests as LightRequests;
14
use DaveRandom\LibLifxLan\Messages\Light\Responses as LightResponses;
15
use DaveRandom\LibLifxLan\Messages\Message;
16
use DaveRandom\LibLifxLan\Messages\UnknownMessage;
17
use Ramsey\Uuid\UuidFactory;
18
use Ramsey\Uuid\UuidFactoryInterface;
19
use function DaveRandom\LibLifxLan\nanotime_to_datetimeimmutable;
20
use function DaveRandom\LibLifxLan\uint16_to_int16;
21
22
final class MessageDecoder
23
{
24
    private const HSBK_FORMAT = 'vhue/vsaturation/vbrightness/vtemperature';
25
26
    private const SET_WAVEFORM_FORMAT
27
        = 'Creserved/Ctransient'
28
        . '/' . self::HSBK_FORMAT
29
        . '/Vperiod/' . \DaveRandom\LibLifxLan\FLOAT32_CODE . 'cycles/vskewRatio/Cwaveform'
30
    ;
31
32
    /**
33
     * @uses decodeAcknowledgement
34
     * @uses decodeEchoRequest
35
     * @uses decodeEchoResponse
36
     * @uses decodeGetGroup
37
     * @uses decodeSetGroup
38
     * @uses decodeStateGroup
39
     * @uses decodeGetHostFirmware
40
     * @uses decodeStateHostFirmware
41
     * @uses decodeGetHostInfo
42
     * @uses decodeStateHostInfo
43
     * @uses decodeGetInfo
44
     * @uses decodeStateInfo
45
     * @uses decodeGetLabel
46
     * @uses decodeSetLabel
47
     * @uses decodeStateLabel
48
     * @uses decodeGetLocation
49
     * @uses decodeSetLocation
50
     * @uses decodeStateLocation
51
     * @uses decodeGetDevicePower
52
     * @uses decodeSetDevicePower
53
     * @uses decodeStateDevicePower
54
     * @uses decodeGetService
55
     * @uses decodeStateService
56
     * @uses decodeGetVersion
57
     * @uses decodeStateVersion
58
     * @uses decodeGetWifiFirmware
59
     * @uses decodeStateWifiFirmware
60
     * @uses decodeGetWifiInfo
61
     * @uses decodeStateWifiInfo
62
     * @uses decodeGet
63
     * @uses decodeSetColor
64
     * @uses decodeSetWaveform
65
     * @uses decodeSetWaveformOptional
66
     * @uses decodeState
67
     * @uses decodeGetInfrared
68
     * @uses decodeSetInfrared
69
     * @uses decodeStateInfrared
70
     * @uses decodeGetLightPower
71
     * @uses decodeSetLightPower
72
     * @uses decodeStateLightPower
73
     */
74
    private const MESSAGE_INFO = [
75
        // Device command messages
76
        DeviceCommands\SetGroup::MESSAGE_TYPE_ID => [DeviceCommands\SetGroup::WIRE_SIZE, 'SetGroup'],
77
        DeviceCommands\SetLabel::MESSAGE_TYPE_ID => [DeviceCommands\SetLabel::WIRE_SIZE, 'SetLabel'],
78
        DeviceCommands\SetLocation::MESSAGE_TYPE_ID => [DeviceCommands\SetLocation::WIRE_SIZE, 'SetLocation'],
79
        DeviceCommands\SetPower::MESSAGE_TYPE_ID => [DeviceCommands\SetPower::WIRE_SIZE, 'SetDevicePower'],
80
81
        // Device request messages
82
        DeviceRequests\EchoRequest::MESSAGE_TYPE_ID => [DeviceRequests\EchoRequest::WIRE_SIZE, 'EchoRequest'],
83
        DeviceRequests\GetGroup::MESSAGE_TYPE_ID => [DeviceRequests\GetGroup::WIRE_SIZE, 'GetGroup'],
84
        DeviceRequests\GetHostFirmware::MESSAGE_TYPE_ID => [DeviceRequests\GetHostFirmware::WIRE_SIZE, 'GetHostFirmware'],
85
        DeviceRequests\GetHostInfo::MESSAGE_TYPE_ID => [DeviceRequests\GetHostInfo::WIRE_SIZE, 'GetHostInfo'],
86
        DeviceRequests\GetInfo::MESSAGE_TYPE_ID => [DeviceRequests\GetInfo::WIRE_SIZE, 'GetInfo'],
87
        DeviceRequests\GetLabel::MESSAGE_TYPE_ID => [DeviceRequests\GetLabel::WIRE_SIZE, 'GetLabel'],
88
        DeviceRequests\GetLocation::MESSAGE_TYPE_ID => [DeviceRequests\GetLocation::WIRE_SIZE, 'GetLocation'],
89
        DeviceRequests\GetPower::MESSAGE_TYPE_ID => [DeviceRequests\GetPower::WIRE_SIZE, 'GetDevicePower'],
90
        DeviceRequests\GetService::MESSAGE_TYPE_ID => [DeviceRequests\GetService::WIRE_SIZE, 'GetService'],
91
        DeviceRequests\GetVersion::MESSAGE_TYPE_ID => [DeviceRequests\GetVersion::WIRE_SIZE, 'GetVersion'],
92
        DeviceRequests\GetWifiFirmware::MESSAGE_TYPE_ID => [DeviceRequests\GetWifiFirmware::WIRE_SIZE, 'GetWifiFirmware'],
93
        DeviceRequests\GetWifiInfo::MESSAGE_TYPE_ID => [DeviceRequests\GetWifiInfo::WIRE_SIZE, 'GetWifiInfo'],
94
95
        // Device response messages
96
        DeviceResponses\Acknowledgement::MESSAGE_TYPE_ID => [DeviceResponses\Acknowledgement::WIRE_SIZE, 'Acknowledgement'],
97
        DeviceResponses\EchoResponse::MESSAGE_TYPE_ID => [DeviceResponses\EchoResponse::WIRE_SIZE, 'EchoResponse'],
98
        DeviceResponses\StateGroup::MESSAGE_TYPE_ID => [DeviceResponses\StateGroup::WIRE_SIZE, 'StateGroup'],
99
        DeviceResponses\StateHostFirmware::MESSAGE_TYPE_ID => [DeviceResponses\StateHostFirmware::WIRE_SIZE, 'StateHostFirmware'],
100
        DeviceResponses\StateHostInfo::MESSAGE_TYPE_ID => [DeviceResponses\StateHostInfo::WIRE_SIZE, 'StateHostInfo'],
101
        DeviceResponses\StateInfo::MESSAGE_TYPE_ID => [DeviceResponses\StateInfo::WIRE_SIZE, 'StateInfo'],
102
        DeviceResponses\StateLabel::MESSAGE_TYPE_ID => [DeviceResponses\StateLabel::WIRE_SIZE, 'StateLabel'],
103
        DeviceResponses\StateLocation::MESSAGE_TYPE_ID => [DeviceResponses\StateLocation::WIRE_SIZE, 'StateLocation'],
104
        DeviceResponses\StatePower::MESSAGE_TYPE_ID => [DeviceResponses\StatePower::WIRE_SIZE, 'StateDevicePower'],
105
        DeviceResponses\StateService::MESSAGE_TYPE_ID => [DeviceResponses\StateService::WIRE_SIZE, 'StateService'],
106
        DeviceResponses\StateVersion::MESSAGE_TYPE_ID => [DeviceResponses\StateVersion::WIRE_SIZE, 'StateVersion'],
107
        DeviceResponses\StateWifiFirmware::MESSAGE_TYPE_ID => [DeviceResponses\StateWifiFirmware::WIRE_SIZE, 'StateWifiFirmware'],
108
        DeviceResponses\StateWifiInfo::MESSAGE_TYPE_ID => [DeviceResponses\StateWifiInfo::WIRE_SIZE, 'StateWifiInfo'],
109
110
        // Light command messages
111
        LightCommmands\SetColor::MESSAGE_TYPE_ID => [LightCommmands\SetColor::WIRE_SIZE, 'SetColor'],
112
        LightCommmands\SetInfrared::MESSAGE_TYPE_ID => [LightCommmands\SetInfrared::WIRE_SIZE, 'SetInfrared'],
113
        LightCommmands\SetPower::MESSAGE_TYPE_ID => [LightCommmands\SetPower::WIRE_SIZE, 'SetLightPower'],
114
        LightCommmands\SetWaveform::MESSAGE_TYPE_ID => [LightCommmands\SetWaveform::WIRE_SIZE, 'SetWaveform'],
115
        LightCommmands\SetWaveformOptional::MESSAGE_TYPE_ID => [LightCommmands\SetWaveformOptional::WIRE_SIZE, 'SetWaveformOptional'],
116
117
        // Light request messages
118
        LightRequests\Get::MESSAGE_TYPE_ID => [LightRequests\Get::WIRE_SIZE, 'Get'],
119
        LightRequests\GetInfrared::MESSAGE_TYPE_ID => [LightRequests\GetInfrared::WIRE_SIZE, 'GetInfrared'],
120
        LightRequests\GetPower::MESSAGE_TYPE_ID => [LightRequests\GetPower::WIRE_SIZE, 'GetLightPower'],
121
122
        // Light response messages
123
        LightResponses\State::MESSAGE_TYPE_ID => [LightResponses\State::WIRE_SIZE, 'State'],
124
        LightResponses\StateInfrared::MESSAGE_TYPE_ID => [LightResponses\StateInfrared::WIRE_SIZE, 'StateInfrared'],
125
        LightResponses\StatePower::MESSAGE_TYPE_ID => [LightResponses\StatePower::WIRE_SIZE, 'StateLightPower'],
126
    ];
127
128
    private $uuidFactory;
129
130
    private function decodeAcknowledgement(): DeviceResponses\Acknowledgement
131
    {
132
        return new DeviceResponses\Acknowledgement();
133
    }
134
135
    private function decodeEchoRequest(string $data, int $offset): DeviceRequests\EchoRequest
136
    {
137
        return new DeviceRequests\EchoRequest(\substr($data, $offset));
138
    }
139
140
    private function decodeEchoResponse(string $data, int $offset): DeviceResponses\EchoResponse
141
    {
142
        return new DeviceResponses\EchoResponse(\substr($data, $offset));
143
    }
144
145
    private function decodeGetGroup(): DeviceRequests\GetGroup
146
    {
147
        return new DeviceRequests\GetGroup;
148
    }
149
150
    private function decodeSetGroup(string $data, int $offset): DeviceCommands\SetGroup
151
    {
152
        [
153
            'guid'    => $guid,
154
            'label'   => $label,
155
            'updated' => $updatedAt,
156
        ] = \unpack('a16guid/a32label/Pupdated', $data, $offset);
157
158
        $guid = $this->uuidFactory->fromBytes($guid);
159
        $updatedAt = nanotime_to_datetimeimmutable($updatedAt);
160
        $label = new DeviceDataTypes\Label(\rtrim($label, "\x00"));
161
162
        return new DeviceCommands\SetGroup(new DeviceDataTypes\Group($guid, $label, $updatedAt));
163
    }
164
165
    private function decodeStateGroup(string $data, int $offset): DeviceResponses\StateGroup
166
    {
167
        [
168
            'guid'    => $guid,
169
            'label'   => $label,
170
            'updated' => $updatedAt,
171
        ] = \unpack('a16guid/a32label/Pupdated', $data, $offset);
172
173
        $guid = $this->uuidFactory->fromBytes($guid);
174
        $updatedAt = nanotime_to_datetimeimmutable($updatedAt);
175
        $label = new DeviceDataTypes\Label(\rtrim($label, "\x00"));
176
177
        return new DeviceResponses\StateGroup(new DeviceDataTypes\Group($guid, $label, $updatedAt));
178
    }
179
180
    private function decodeGetHostFirmware(): DeviceRequests\GetHostFirmware
181
    {
182
        return new DeviceRequests\GetHostFirmware;
183
    }
184
185
    private function decodeStateHostFirmware(string $data, int $offset): DeviceResponses\StateHostFirmware
186
    {
187
        [
188
            'build'    => $build,
189
            'version'  => $version,
190
        ] = \unpack('Pbuild/Preserved/Vversion', $data, $offset);
191
192
        $build = nanotime_to_datetimeimmutable($build);
193
194
        return new DeviceResponses\StateHostFirmware(new DeviceDataTypes\HostFirmware($build, $version));
195
    }
196
197
    private function decodeGetHostInfo(): DeviceRequests\GetHostInfo
198
    {
199
        return new DeviceRequests\GetHostInfo;
200
    }
201
202
    private function decodeStateHostInfo(string $data, int $offset): DeviceResponses\StateHostInfo
203
    {
204
        [
205
            'signal'   => $signal,
206
            'tx'       => $tx,
207
            'rx'       => $rx,
208
        ] = \unpack(\DaveRandom\LibLifxLan\FLOAT32_CODE . 'signal/Vtx/Vrx/vreserved', $data, $offset);
209
210
        return new DeviceResponses\StateHostInfo(new DeviceDataTypes\HostInfo($signal, $tx, $rx));
211
    }
212
213
    private function decodeGetInfo(): DeviceRequests\GetInfo
214
    {
215
        return new DeviceRequests\GetInfo;
216
    }
217
218
    private function decodeStateInfo(string $data, int $offset): DeviceResponses\StateInfo
219
    {
220
        [
221
            'time'     => $time,
222
            'uptime'   => $uptime,
223
            'downtime' => $downtime,
224
        ] = \unpack('Ptime/Puptime/Pdowntime', $data, $offset);
225
226
        $time = nanotime_to_datetimeimmutable($time);
227
228
        return new DeviceResponses\StateInfo(new DeviceDataTypes\TimeInfo($time, $uptime, $downtime));
229
    }
230
231
    private function decodeGetLabel(): DeviceRequests\GetLabel
232
    {
233
        return new DeviceRequests\GetLabel;
234
    }
235
236
    private function decodeSetLabel(string $data, int $offset): DeviceCommands\SetLabel
237
    {
238
        return new DeviceCommands\SetLabel(new DeviceDataTypes\Label(\rtrim(\substr($data, $offset), "\x00")));
239
    }
240
241
    private function decodeStateLabel(string $data, int $offset): DeviceResponses\StateLabel
242
    {
243
        return new DeviceResponses\StateLabel(new DeviceDataTypes\Label(\rtrim(\substr($data, $offset), "\x00")));
244
    }
245
246
    private function decodeGetLocation(): DeviceRequests\GetLocation
247
    {
248
        return new DeviceRequests\GetLocation;
249
    }
250
251
    private function decodeSetLocation(string $data, int $offset): DeviceCommands\SetLocation
252
    {
253
        [
254
            'guid'    => $guid,
255
            'label'   => $label,
256
            'updated' => $updatedAt,
257
        ] = \unpack('a16guid/a32label/Pupdated', $data, $offset);
258
259
        $guid = $this->uuidFactory->fromBytes($guid);
260
        $updatedAt = nanotime_to_datetimeimmutable($updatedAt);
261
        $label = new DeviceDataTypes\Label(\rtrim($label, "\x00"));
262
263
        return new DeviceCommands\SetLocation(new DeviceDataTypes\Location($guid, $label, $updatedAt));
264
    }
265
266
    private function decodeStateLocation(string $data, int $offset): DeviceResponses\StateLocation
267
    {
268
        [
269
            'guid'    => $guid,
270
            'label'   => $label,
271
            'updated' => $updatedAt,
272
        ] = \unpack('a16guid/a32label/Pupdated', $data, $offset);
273
274
        $guid = $this->uuidFactory->fromBytes($guid);
275
        $updatedAt = nanotime_to_datetimeimmutable($updatedAt);
276
        $label = new DeviceDataTypes\Label(\rtrim($label, "\x00"));
277
278
        return new DeviceResponses\StateLocation(new DeviceDataTypes\Location($guid, $label, $updatedAt));
279
    }
280
281
    private function decodeGetDevicePower(): DeviceRequests\GetPower
282
    {
283
        return new DeviceRequests\GetPower;
284
    }
285
286
    private function decodeSetDevicePower(string $data, int $offset): DeviceCommands\SetPower
287
    {
288
        $level = \unpack('vlevel', $data, $offset)['level'];
289
290
        return new DeviceCommands\SetPower($level);
291
    }
292
293
    private function decodeStateDevicePower(string $data, int $offset): DeviceResponses\StatePower
294
    {
295
        $level = \unpack('vlevel', $data, $offset)['level'];
296
297
        return new DeviceResponses\StatePower($level);
298
    }
299
300
    private function decodeGetService(): DeviceRequests\GetService
301
    {
302
        return new DeviceRequests\GetService;
303
    }
304
305
    private function decodeStateService(string $data, int $offset): DeviceResponses\StateService
306
    {
307
        [
308
            'serviceType' => $serviceType,
309
            'port' => $port,
310
        ] = \unpack('CserviceType/Vport', $data, $offset);
311
312
        return new DeviceResponses\StateService(new DeviceDataTypes\Service($serviceType, $port));
313
    }
314
315
    private function decodeGetVersion(): DeviceRequests\GetVersion
316
    {
317
        return new DeviceRequests\GetVersion;
318
    }
319
320
    private function decodeStateVersion(string $data, int $offset): DeviceResponses\StateVersion
321
    {
322
        [
323
            'vendor'  => $vendor,
324
            'product' => $product,
325
            'version' => $version,
326
        ] = \unpack('Vvendor/Vproduct/Vversion', $data, $offset);
327
328
        return new DeviceResponses\StateVersion(new DeviceDataTypes\Version($vendor, $product, $version));
329
    }
330
331
    private function decodeGetWifiFirmware(): DeviceRequests\GetWifiFirmware
332
    {
333
        return new DeviceRequests\GetWifiFirmware;
334
    }
335
336
    private function decodeStateWifiFirmware(string $data, int $offset): DeviceResponses\StateWifiFirmware
337
    {
338
        [
339
            'build'    => $build,
340
            'version'  => $version,
341
        ] = \unpack('Pbuild/Preserved/Vversion', $data, $offset);
342
343
        $build = nanotime_to_datetimeimmutable($build);
344
345
        return new DeviceResponses\StateWifiFirmware(new DeviceDataTypes\WifiFirmware($build, $version));
346
    }
347
348
    private function decodeGetWifiInfo(): DeviceRequests\GetWifiInfo
349
    {
350
        return new DeviceRequests\GetWifiInfo;
351
    }
352
353
    private function decodeStateWifiInfo(string $data, int $offset): DeviceResponses\StateWifiInfo
354
    {
355
356
        [
357
            'signal'   => $signal,
358
            'tx'       => $tx,
359
            'rx'       => $rx,
360
        ] = \unpack(\DaveRandom\LibLifxLan\FLOAT32_CODE . 'signal/Vtx/Vrx/vreserved', $data, $offset);
361
362
        return new DeviceResponses\StateWifiInfo(new DeviceDataTypes\WifiInfo($signal, $tx, $rx));
363
    }
364
365
    private function decodeGet(): LightRequests\Get
366
    {
367
        return new LightRequests\Get;
368
    }
369
370 4
    private function decodeSetColor(string $data, int $offset): LightCommmands\SetColor
371
    {
372
        [
373 4
            'hue'         => $hue,
374 4
            'saturation'  => $saturation,
375 4
            'brightness'  => $brightness,
376 4
            'temperature' => $temperature,
377 4
            'duration'    => $duration,
378 4
        ] = \unpack('Creserved/' . self::HSBK_FORMAT . '/Vduration', $data, $offset);
379
380 4
        $color = new LightDataTypes\HsbkColor($hue, $saturation, $brightness, $temperature);
381
382 4
        return new LightCommmands\SetColor(new LightDataTypes\ColorTransition($color, $duration));
383
    }
384
385
    private function decodeSetWaveform(string $data, int $offset): LightCommmands\SetWaveform
386
    {
387
        [
388
            'transient' => $transient,
389
            'hue' => $hue, 'saturation' => $saturation, 'brightness' => $brightness, 'temperature' => $temperature,
390
            'period' => $period, 'cycles' => $cycles, 'skewRatio' => $skewRatio, 'waveform' => $waveform,
391
        ] = \unpack(self::SET_WAVEFORM_FORMAT, $data, $offset);
392
393
        $color = new LightDataTypes\HsbkColor($hue, $saturation, $brightness, $temperature);
394
395
        $skewRatio = uint16_to_int16($skewRatio);
396
        $effect = new LightDataTypes\Effect((bool)$transient, $color, $period, $cycles, $skewRatio, $waveform);
397
398
        return new LightCommmands\SetWaveform($effect);
399
    }
400
401
    private function decodeSetWaveformOptional(string $data, int $offset): LightCommmands\SetWaveformOptional
402
    {
403
        [
404
            'transient' => $transient,
405
            'hue' => $hue, 'saturation' => $saturation, 'brightness' => $brightness, 'temperature' => $temperature,
406
            'period' => $period, 'cycles' => $cycles, 'skewRatio' => $skewRatio, 'waveform' => $waveform,
407
            'setH' => $setHue, 'setS' => $setSaturation, 'setB' => $setBrightness, 'setK' => $setTemperature,
408
        ] = \unpack(self::SET_WAVEFORM_FORMAT . '/CsetH/CsetS/CsetB/CsetK', $data, $offset);
409
410
        $color = new LightDataTypes\HsbkColor($hue, $saturation, $brightness, $temperature);
411
        $skewRatio = uint16_to_int16($skewRatio);
412
413
        $options = ($setHue ? LightDataTypes\Effect::SET_HUE : 0)
414
            | ($setSaturation ? LightDataTypes\Effect::SET_SATURATION : 0)
415
            | ($setBrightness ? LightDataTypes\Effect::SET_BRIGHTNESS : 0)
416
            | ($setTemperature ? LightDataTypes\Effect::SET_TEMPERATURE : 0);
417
418
        $effect = new LightDataTypes\Effect((bool)$transient, $color, $period, $cycles, $skewRatio, $waveform, $options);
419
420
        return new LightCommmands\SetWaveformOptional($effect);
421
    }
422
423
    private function decodeState(string $data, int $offset): LightResponses\State
424
    {
425
        [
426
            'hue'         => $hue,
427
            'saturation'  => $saturation,
428
            'brightness'  => $brightness,
429
            'temperature' => $temperature,
430
            'power'       => $power,
431
            'label'       => $label,
432
        ] = \unpack(self::HSBK_FORMAT . '/vreserved/vpower/a32label/Preserved', $data, $offset);
433
434
        $color = new LightDataTypes\HsbkColor($hue, $saturation, $brightness, $temperature);
435
        $label = new DeviceDataTypes\Label(\rtrim($label, "\x00"));
436
437
        return new LightResponses\State(new LightDataTypes\State($color, $power, $label));
438
    }
439
440
    private function decodeGetInfrared(): LightRequests\GetInfrared
441
    {
442
        return new LightRequests\GetInfrared;
443
    }
444
445
    private function decodeSetInfrared(string $data, int $offset): LightCommmands\SetInfrared
446
    {
447
        $level = \unpack('vlevel', $data, $offset)['level'];
448
449
        return new LightCommmands\SetInfrared($level);
450
    }
451
452
    private function decodeStateInfrared(string $data, int $offset): LightResponses\StateInfrared
453
    {
454
        $level = \unpack('vlevel', $data, $offset)['level'];
455
456
        return new LightResponses\StateInfrared($level);
457
    }
458
459
    private function decodeGetLightPower(): LightRequests\GetPower
460
    {
461
        return new LightRequests\GetPower;
462
    }
463
464
    private function decodeSetLightPower(string $data, int $offset): LightCommmands\SetPower
465
    {
466
        [
467
            'level'    => $level,
468
            'duration' => $duration,
469
        ] = \unpack('vlevel/Vduration', $data, $offset);
470
471
        return new LightCommmands\SetPower(new LightDataTypes\PowerTransition($level, $duration));
472
    }
473
474
    private function decodeStateLightPower(string $data, int $offset): LightResponses\StatePower
475
    {
476
        $level = \unpack('vlevel', $data, $offset)['level'];
477
478
        return new LightResponses\StatePower($level);
479
    }
480
481 16
    public function __construct(UuidFactoryInterface $uuidFactory = null)
482
    {
483 16
        $this->uuidFactory = $uuidFactory ?? new UuidFactory;
484
    }
485
486
    /**
487
     * @param int $type
488
     * @param string $data
489
     * @param int $offset
490
     * @param int|null $dataLength
491
     * @return Message
492
     * @throws DecodingException
493
     */
494 4
    public function decodeMessage(int $type, string $data, int $offset = 0, int $dataLength = null): Message
495
    {
496 4
        $dataLength = $dataLength ?? (\strlen($data) - $offset);
497
498 4
        if (!\array_key_exists($type, self::MESSAGE_INFO)) {
499
            return new UnknownMessage($type, \substr($data, $offset, $dataLength));
500
        }
501
502 4
        [$expectedLength, $messageName] = self::MESSAGE_INFO[$type];
503
504 4
        if ($dataLength !== $expectedLength) {
505
            throw new InvalidMessagePayloadLengthException(
506
                "Invalid payload length for {$messageName} message,"
507
                . " expecting {$expectedLength} bytes, got {$dataLength} bytes"
508
            );
509
        }
510
511 4
        return ([$this, 'decode' . $messageName])($data, $offset);
512
    }
513
}
514