13
13
*/
14
14
class MiIO
15
15
{
16
- const CACHE_KEY = 'MiIO ' ;
17
-
18
- const PORT = 54321 ;
19
-
20
- const TIMEOUT = 5 ;
21
-
22
- const INFO = 'miIO.info ' ;
23
-
24
- /**
25
- * @param Device $device
26
- */
27
- public function getInfo ( Device $ device )
28
- {
29
- $ response = $ this -> send ( $ device , static :: INFO );
30
- }
31
-
32
- /**
33
- * @param Device $device
34
- * @return Device|null
35
- */
36
- private function init ( Device & $ device )
37
- {
38
- if ( strlen ( $ device -> getIpAddress ())) {
39
- /** @var Packet $packet */
40
- $ packet = app ( Packet::class );
41
- $ helo = $ packet ->getHelo ();
42
-
43
- $ start = time ();
44
- $ socket = socket_create (AF_INET , SOCK_DGRAM , SOL_UDP );
45
-
46
- while (time () < ($ start + 10 )) {
47
- $ response = $ this ->getSocketResponse ($ device ->getIpAddress (), $ socket , $ helo );
48
-
49
- if (!empty ($ response )) {
50
- $ response = bin2hex ($ response );
51
- }
52
-
53
- if (!empty ($ response )) {
54
- $ packet = new Packet ($ response );
55
- if ($ packet ->getDeviceType ()
56
- && $ packet ->getSerial ()) {
57
- $ device ->setDeviceType ($ packet ->getDeviceType ());
58
- $ device ->setSerial ($ packet ->getSerial ());
59
- $ device ->setTimeDelta (hexdec ($ packet ->getTimestamp ()) - time ());
60
- socket_close ($ socket );
61
-
62
- return $ device ;
63
- }
64
- }
65
- }
66
- if ($ socket ) {
67
- socket_close ($ socket );
68
- }
69
- }
70
-
71
- return null ;
72
- }
73
-
74
- /**
75
- * @param Device $device
76
- * @param string $command
77
- * @param array $params
78
- * @return array
79
- */
80
- public function send (Device $ device , $ command , $ params = [])
81
- {
82
- if (!$ device ->isInitialized ()) {
83
- $ this ->init ($ device );
84
- }
85
-
86
- if (!$ device ->isInitialized ()) {
87
- return [];
88
- }
89
-
90
- $ request = new Request ();
91
- $ request
92
- ->setMethod ($ command )
93
- ->setParams ($ params );
94
-
95
- return $ this ->getResponse ($ device , $ request );
96
- }
97
-
98
- /**
99
- * @param Device $device
100
- * @param Request $request
101
- * @return array
102
- */
103
- public function getResponse (Device $ device , Request $ request )
104
- {
105
- $ cacheKey = static ::CACHE_KEY . $ device ->getIpAddress ();
106
- $ requestId = (int )\Cache::get ($ cacheKey );
107
- \Cache::forever ($ cacheKey , $ requestId + 1 );
108
-
109
- $ request ->setId ($ requestId );
110
-
111
- $ data = $ device ->encrypt ($ request );
112
-
113
- $ packet = new Packet ();
114
- $ packet
115
- ->setData ($ data )
116
- ->setDevice ($ device );
117
-
118
- $ start = time ();
119
- $ socket = socket_create (AF_INET , SOCK_DGRAM , SOL_UDP );
120
-
121
- while (time () < ($ start + 10 )) {
122
- $ packet ->setTimestamp ($ device ->getTimeDelta () + time ());
123
- $ response = $ this ->getSocketResponse ($ device ->getIpAddress (), $ socket , (string )$ packet );
124
-
125
- if (!empty ($ response )) {
126
- $ response = bin2hex ($ response );
127
- }
128
-
129
- $ result = $ this ->decrypt ($ device , $ response );
130
-
131
- if (strlen ($ result )) {
132
- $ response = json_decode (preg_replace ('/[\x00-\x1F\x7F]/ ' , '' , $ result ), true );
133
-
134
- if (!empty ($ response ['id ' ]) && $ response ['id ' ] === $ requestId ) {
135
- socket_close ($ socket );
136
-
137
- return $ response ;
138
- }
139
- }
140
- }
141
-
142
- return [];
143
- }
144
-
145
- /**
146
- * @param string $ip
147
- * @param \Resource $socket
148
- * @param string $data
149
- * @return string|null
150
- */
151
- private function getSocketResponse ($ ip , $ socket , $ data )
152
- {
153
- if (ctype_xdigit ($ data )) {
154
- $ data = hex2bin ($ data );
155
- }
156
-
157
- $ buf = null ;
158
-
159
- try {
160
- socket_set_option ($ socket , SOL_SOCKET , SO_BROADCAST , 1 );
161
- socket_set_option ($ socket , SOL_SOCKET , SO_RCVTIMEO , ['sec ' => 5 , 'usec ' => 0 ]);
162
-
163
- socket_sendto ($ socket , $ data , strlen ($ data ), 0 , $ ip , static ::PORT );
164
-
165
- socket_recvfrom ($ socket , $ buf , 1024 , 0 , $ name , $ port );
166
- } catch (\Throwable $ e ) {
167
- }
168
-
169
- return $ buf ;
170
- }
171
-
172
- /**
173
- * @param Device $device
174
- * @param string $response
175
- * @return string
176
- */
177
- private function decrypt (Device $ device , $ response )
178
- {
179
- if (!empty ($ response )) {
180
- $ packet = new Packet ($ response );
181
-
182
- return $ device ->decrypt ($ packet ->getData ());
183
- }
184
-
185
- return '' ;
186
- }
16
+ const CACHE_KEY = 'MiIO ' ;
17
+
18
+ const PORT = 54321 ;
19
+
20
+ const TIMEOUT = 5 ;
21
+
22
+ const INFO = 'miIO.info ' ;
23
+
24
+ /**
25
+ * @param Device $device
26
+ * @return array
27
+ */
28
+ public function getInfo ( Device $ device )
29
+ {
30
+ return $ this -> send ( $ device , static :: INFO );
31
+ }
32
+
33
+ /**
34
+ * @param Device $device
35
+ * @return Device|null
36
+ */
37
+ private function init ( Device & $ device )
38
+ {
39
+ if ( strlen ( $ device -> getIpAddress ())) {
40
+ $ packet = new Packet ( );
41
+ $ helo = $ packet ->getHelo ();
42
+
43
+ $ start = time ();
44
+ $ socket = socket_create (AF_INET , SOCK_DGRAM , SOL_UDP );
45
+
46
+ while (time () < ($ start + 10 )) {
47
+ $ response = $ this ->getSocketResponse ($ device ->getIpAddress (), $ socket , $ helo );
48
+
49
+ if (!empty ($ response )) {
50
+ $ response = bin2hex ($ response );
51
+ }
52
+
53
+ if (!empty ($ response )) {
54
+ $ packet = new Packet ($ response );
55
+ if ($ packet ->getDeviceType ()
56
+ && $ packet ->getSerial ()) {
57
+ $ device ->setDeviceType ($ packet ->getDeviceType ());
58
+ $ device ->setSerial ($ packet ->getSerial ());
59
+ $ device ->setTimeDelta (hexdec ($ packet ->getTimestamp ()) - time ());
60
+ socket_close ($ socket );
61
+
62
+ return $ device ;
63
+ }
64
+ }
65
+ }
66
+ if ($ socket ) {
67
+ socket_close ($ socket );
68
+ }
69
+ }
70
+
71
+ return null ;
72
+ }
73
+
74
+ /**
75
+ * @param Device $device
76
+ * @param string $command
77
+ * @param array $params
78
+ * @return array
79
+ */
80
+ public function send (Device $ device , $ command , $ params = [])
81
+ {
82
+ if (!$ device ->isInitialized ()) {
83
+ $ this ->init ($ device );
84
+ }
85
+
86
+ if (!$ device ->isInitialized ()) {
87
+ return [];
88
+ }
89
+
90
+ $ request = new Request ();
91
+ $ request
92
+ ->setMethod ($ command )
93
+ ->setParams ($ params );
94
+
95
+ return $ this ->getResponse ($ device , $ request );
96
+ }
97
+
98
+ /**
99
+ * @param Device $device
100
+ * @param Request $request
101
+ * @return array
102
+ */
103
+ public function getResponse (Device $ device , Request $ request )
104
+ {
105
+ $ cacheKey = static ::CACHE_KEY . $ device ->getIpAddress ();
106
+ $ requestId = (int )\Cache::get ($ cacheKey );
107
+ \Cache::forever ($ cacheKey , $ requestId + 1 );
108
+
109
+ $ request ->setId ($ requestId );
110
+
111
+ $ data = $ device ->encrypt ($ request );
112
+
113
+ $ packet = new Packet ();
114
+ $ packet
115
+ ->setData ($ data )
116
+ ->setDevice ($ device );
117
+
118
+ $ start = time ();
119
+ $ socket = socket_create (AF_INET , SOCK_DGRAM , SOL_UDP );
120
+
121
+ while (time () < ($ start + 10 )) {
122
+ $ packet ->setTimestamp ($ device ->getTimeDelta () + time ());
123
+ $ response = $ this ->getSocketResponse ($ device ->getIpAddress (), $ socket , (string )$ packet );
124
+
125
+ if (!empty ($ response )) {
126
+ $ response = bin2hex ($ response );
127
+ }
128
+
129
+ $ result = $ this ->decrypt ($ device , $ response );
130
+
131
+ if (strlen ($ result )) {
132
+ $ response = json_decode (preg_replace ('/[\x00-\x1F\x7F]/ ' , '' , $ result ), true );
133
+
134
+ if (!empty ($ response ['id ' ]) && $ response ['id ' ] === $ requestId ) {
135
+ socket_close ($ socket );
136
+
137
+ return $ response ;
138
+ }
139
+ }
140
+ }
141
+
142
+ return [];
143
+ }
144
+
145
+ /**
146
+ * @param string $ip
147
+ * @param \Resource $socket
148
+ * @param string $data
149
+ * @return string|null
150
+ */
151
+ private function getSocketResponse ($ ip , $ socket , $ data )
152
+ {
153
+ if (ctype_xdigit ($ data )) {
154
+ $ data = hex2bin ($ data );
155
+ }
156
+
157
+ $ buf = null ;
158
+
159
+ try {
160
+ socket_set_option ($ socket , SOL_SOCKET , SO_BROADCAST , 1 );
161
+ socket_set_option ($ socket , SOL_SOCKET , SO_RCVTIMEO , ['sec ' => 5 , 'usec ' => 0 ]);
162
+
163
+ socket_sendto ($ socket , $ data , strlen ($ data ), 0 , $ ip , static ::PORT );
164
+
165
+ socket_recvfrom ($ socket , $ buf , 1024 , 0 , $ name , $ port );
166
+ } catch (\Throwable $ e ) {
167
+ }
168
+
169
+ return $ buf ;
170
+ }
171
+
172
+ /**
173
+ * @param Device $device
174
+ * @param string $response
175
+ * @return string
176
+ */
177
+ private function decrypt (Device $ device , $ response )
178
+ {
179
+ if (!empty ($ response )) {
180
+ $ packet = new Packet ($ response );
181
+
182
+ return $ device ->decrypt ($ packet ->getData ());
183
+ }
184
+
185
+ return '' ;
186
+ }
187
187
}
0 commit comments