├── .gitattributes
├── .gitignore
├── .travis.yml
├── composer.json
├── composer.lock
├── examples
├── callFunction.php
├── claimDevice.php
├── deleteDevice.php
├── deleteToken.php
├── deleteWebhook.php
├── getDeviceInfo.php
├── getDeviceInfoInProduct.php
├── getToken.php
├── getVariable.php
├── listDevices.php
├── listDevicesInProduct.php
├── listTokens.php
├── listWebhooks.php
├── newAccessToken.php
├── newWebhook.php
├── setDeviceName.php
├── signalDevice.php
├── tinker.bin
├── tinker.cpp
└── uploadFirmware.php
├── phpParticle.class.php
├── phpParticle.config.sample.php
├── phpParticle.firmware.cpp
├── phpunit.xml
├── readme.md
├── src
└── ParticleAPI.php
└── tests
└── ParticleAPITest.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore the actual config file
2 | phpParticle.config.php
3 | vendor/
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - hhvm
8 |
9 | before_script:
10 | - composer self-update
11 | - composer install --prefer-source --no-interaction --dev
12 |
13 | script: phpunit
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "articfox1986/phpparticle",
3 | "description": "A php package for working with the particle API",
4 | "license": "MIT",
5 | "keywords": ["particle","php"],
6 | "authors": [
7 | {
8 | "name": "Devin Pearson",
9 | "email": "devin@blackhat.co.za"
10 | },
11 | {
12 | "name": "Harrison Jones",
13 | "email": "harrison@hhj.me"
14 | }
15 | ],
16 | "require": {},
17 | "require-dev": {
18 | "phpunit/phpunit": "4.0.*"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "articfox1986\\phpparticle\\": "src"
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "3a855fa0bd364da6c971236f33c0f2e5",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "phpunit/php-code-coverage",
12 | "version": "2.0.17",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
16 | "reference": "c4e8e7725e351184a76544634855b8a9c405a6e3"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c4e8e7725e351184a76544634855b8a9c405a6e3",
21 | "reference": "c4e8e7725e351184a76544634855b8a9c405a6e3",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": ">=5.3.3",
26 | "phpunit/php-file-iterator": "~1.3",
27 | "phpunit/php-text-template": "~1.2",
28 | "phpunit/php-token-stream": "~1.3",
29 | "sebastian/environment": "~1.0",
30 | "sebastian/version": "~1.0"
31 | },
32 | "require-dev": {
33 | "ext-xdebug": ">=2.1.4",
34 | "phpunit/phpunit": "~4"
35 | },
36 | "suggest": {
37 | "ext-dom": "*",
38 | "ext-xdebug": ">=2.2.1",
39 | "ext-xmlwriter": "*"
40 | },
41 | "type": "library",
42 | "extra": {
43 | "branch-alias": {
44 | "dev-master": "2.0.x-dev"
45 | }
46 | },
47 | "autoload": {
48 | "classmap": [
49 | "src/"
50 | ]
51 | },
52 | "notification-url": "https://packagist.org/downloads/",
53 | "license": [
54 | "BSD-3-Clause"
55 | ],
56 | "authors": [
57 | {
58 | "name": "Sebastian Bergmann",
59 | "email": "sb@sebastian-bergmann.de",
60 | "role": "lead"
61 | }
62 | ],
63 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
64 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
65 | "keywords": [
66 | "coverage",
67 | "testing",
68 | "xunit"
69 | ],
70 | "time": "2015-05-25 05:11:59"
71 | },
72 | {
73 | "name": "phpunit/php-file-iterator",
74 | "version": "1.3.4",
75 | "source": {
76 | "type": "git",
77 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
78 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
79 | },
80 | "dist": {
81 | "type": "zip",
82 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
83 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
84 | "shasum": ""
85 | },
86 | "require": {
87 | "php": ">=5.3.3"
88 | },
89 | "type": "library",
90 | "autoload": {
91 | "classmap": [
92 | "File/"
93 | ]
94 | },
95 | "notification-url": "https://packagist.org/downloads/",
96 | "include-path": [
97 | ""
98 | ],
99 | "license": [
100 | "BSD-3-Clause"
101 | ],
102 | "authors": [
103 | {
104 | "name": "Sebastian Bergmann",
105 | "email": "sb@sebastian-bergmann.de",
106 | "role": "lead"
107 | }
108 | ],
109 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
110 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
111 | "keywords": [
112 | "filesystem",
113 | "iterator"
114 | ],
115 | "time": "2013-10-10 15:34:57"
116 | },
117 | {
118 | "name": "phpunit/php-text-template",
119 | "version": "1.2.1",
120 | "source": {
121 | "type": "git",
122 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
123 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
124 | },
125 | "dist": {
126 | "type": "zip",
127 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
128 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
129 | "shasum": ""
130 | },
131 | "require": {
132 | "php": ">=5.3.3"
133 | },
134 | "type": "library",
135 | "autoload": {
136 | "classmap": [
137 | "src/"
138 | ]
139 | },
140 | "notification-url": "https://packagist.org/downloads/",
141 | "license": [
142 | "BSD-3-Clause"
143 | ],
144 | "authors": [
145 | {
146 | "name": "Sebastian Bergmann",
147 | "email": "sebastian@phpunit.de",
148 | "role": "lead"
149 | }
150 | ],
151 | "description": "Simple template engine.",
152 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
153 | "keywords": [
154 | "template"
155 | ],
156 | "time": "2015-06-21 13:50:34"
157 | },
158 | {
159 | "name": "phpunit/php-timer",
160 | "version": "1.0.7",
161 | "source": {
162 | "type": "git",
163 | "url": "https://github.com/sebastianbergmann/php-timer.git",
164 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
165 | },
166 | "dist": {
167 | "type": "zip",
168 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
169 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
170 | "shasum": ""
171 | },
172 | "require": {
173 | "php": ">=5.3.3"
174 | },
175 | "type": "library",
176 | "autoload": {
177 | "classmap": [
178 | "src/"
179 | ]
180 | },
181 | "notification-url": "https://packagist.org/downloads/",
182 | "license": [
183 | "BSD-3-Clause"
184 | ],
185 | "authors": [
186 | {
187 | "name": "Sebastian Bergmann",
188 | "email": "sb@sebastian-bergmann.de",
189 | "role": "lead"
190 | }
191 | ],
192 | "description": "Utility class for timing",
193 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
194 | "keywords": [
195 | "timer"
196 | ],
197 | "time": "2015-06-21 08:01:12"
198 | },
199 | {
200 | "name": "phpunit/php-token-stream",
201 | "version": "1.4.8",
202 | "source": {
203 | "type": "git",
204 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
205 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
206 | },
207 | "dist": {
208 | "type": "zip",
209 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
210 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
211 | "shasum": ""
212 | },
213 | "require": {
214 | "ext-tokenizer": "*",
215 | "php": ">=5.3.3"
216 | },
217 | "require-dev": {
218 | "phpunit/phpunit": "~4.2"
219 | },
220 | "type": "library",
221 | "extra": {
222 | "branch-alias": {
223 | "dev-master": "1.4-dev"
224 | }
225 | },
226 | "autoload": {
227 | "classmap": [
228 | "src/"
229 | ]
230 | },
231 | "notification-url": "https://packagist.org/downloads/",
232 | "license": [
233 | "BSD-3-Clause"
234 | ],
235 | "authors": [
236 | {
237 | "name": "Sebastian Bergmann",
238 | "email": "sebastian@phpunit.de"
239 | }
240 | ],
241 | "description": "Wrapper around PHP's tokenizer extension.",
242 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
243 | "keywords": [
244 | "tokenizer"
245 | ],
246 | "time": "2015-09-15 10:49:45"
247 | },
248 | {
249 | "name": "phpunit/phpunit",
250 | "version": "4.0.20",
251 | "source": {
252 | "type": "git",
253 | "url": "https://github.com/sebastianbergmann/phpunit.git",
254 | "reference": "de121ce8708b7ac7f628603d7682d0d57f528345"
255 | },
256 | "dist": {
257 | "type": "zip",
258 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de121ce8708b7ac7f628603d7682d0d57f528345",
259 | "reference": "de121ce8708b7ac7f628603d7682d0d57f528345",
260 | "shasum": ""
261 | },
262 | "require": {
263 | "ext-dom": "*",
264 | "ext-json": "*",
265 | "ext-pcre": "*",
266 | "ext-reflection": "*",
267 | "ext-spl": "*",
268 | "php": ">=5.3.3",
269 | "phpunit/php-code-coverage": ">=2.0.0,<2.1.0",
270 | "phpunit/php-file-iterator": "~1.3.1",
271 | "phpunit/php-text-template": "~1.2",
272 | "phpunit/php-timer": "~1.0.2",
273 | "phpunit/phpunit-mock-objects": ">=2.0.0,<2.1.0",
274 | "sebastian/diff": "~1.1",
275 | "sebastian/environment": "~1.0",
276 | "sebastian/exporter": "~1.0.1",
277 | "sebastian/version": "~1.0.3",
278 | "symfony/yaml": "~2.0"
279 | },
280 | "suggest": {
281 | "phpunit/php-invoker": "~1.1"
282 | },
283 | "bin": [
284 | "phpunit"
285 | ],
286 | "type": "library",
287 | "extra": {
288 | "branch-alias": {
289 | "dev-master": "4.0.x-dev"
290 | }
291 | },
292 | "autoload": {
293 | "classmap": [
294 | "src/"
295 | ]
296 | },
297 | "notification-url": "https://packagist.org/downloads/",
298 | "include-path": [
299 | "",
300 | "../../symfony/yaml/"
301 | ],
302 | "license": [
303 | "BSD-3-Clause"
304 | ],
305 | "authors": [
306 | {
307 | "name": "Sebastian Bergmann",
308 | "email": "sebastian@phpunit.de",
309 | "role": "lead"
310 | }
311 | ],
312 | "description": "The PHP Unit Testing framework.",
313 | "homepage": "http://www.phpunit.de/",
314 | "keywords": [
315 | "phpunit",
316 | "testing",
317 | "xunit"
318 | ],
319 | "time": "2014-05-02 07:19:37"
320 | },
321 | {
322 | "name": "phpunit/phpunit-mock-objects",
323 | "version": "2.0.10",
324 | "source": {
325 | "type": "git",
326 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
327 | "reference": "e60bb929c50ae4237aaf680a4f6773f4ee17f0a2"
328 | },
329 | "dist": {
330 | "type": "zip",
331 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e60bb929c50ae4237aaf680a4f6773f4ee17f0a2",
332 | "reference": "e60bb929c50ae4237aaf680a4f6773f4ee17f0a2",
333 | "shasum": ""
334 | },
335 | "require": {
336 | "php": ">=5.3.3",
337 | "phpunit/php-text-template": "~1.2"
338 | },
339 | "require-dev": {
340 | "phpunit/phpunit": ">=4.0.0,<4.1.0"
341 | },
342 | "suggest": {
343 | "ext-soap": "*"
344 | },
345 | "type": "library",
346 | "extra": {
347 | "branch-alias": {
348 | "dev-master": "2.0.x-dev"
349 | }
350 | },
351 | "autoload": {
352 | "classmap": [
353 | "src/"
354 | ]
355 | },
356 | "notification-url": "https://packagist.org/downloads/",
357 | "include-path": [
358 | ""
359 | ],
360 | "license": [
361 | "BSD-3-Clause"
362 | ],
363 | "authors": [
364 | {
365 | "name": "Sebastian Bergmann",
366 | "email": "sb@sebastian-bergmann.de",
367 | "role": "lead"
368 | }
369 | ],
370 | "description": "Mock Object library for PHPUnit",
371 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
372 | "keywords": [
373 | "mock",
374 | "xunit"
375 | ],
376 | "time": "2014-06-12 07:19:48"
377 | },
378 | {
379 | "name": "sebastian/diff",
380 | "version": "1.3.0",
381 | "source": {
382 | "type": "git",
383 | "url": "https://github.com/sebastianbergmann/diff.git",
384 | "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
385 | },
386 | "dist": {
387 | "type": "zip",
388 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
389 | "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
390 | "shasum": ""
391 | },
392 | "require": {
393 | "php": ">=5.3.3"
394 | },
395 | "require-dev": {
396 | "phpunit/phpunit": "~4.2"
397 | },
398 | "type": "library",
399 | "extra": {
400 | "branch-alias": {
401 | "dev-master": "1.3-dev"
402 | }
403 | },
404 | "autoload": {
405 | "classmap": [
406 | "src/"
407 | ]
408 | },
409 | "notification-url": "https://packagist.org/downloads/",
410 | "license": [
411 | "BSD-3-Clause"
412 | ],
413 | "authors": [
414 | {
415 | "name": "Kore Nordmann",
416 | "email": "mail@kore-nordmann.de"
417 | },
418 | {
419 | "name": "Sebastian Bergmann",
420 | "email": "sebastian@phpunit.de"
421 | }
422 | ],
423 | "description": "Diff implementation",
424 | "homepage": "http://www.github.com/sebastianbergmann/diff",
425 | "keywords": [
426 | "diff"
427 | ],
428 | "time": "2015-02-22 15:13:53"
429 | },
430 | {
431 | "name": "sebastian/environment",
432 | "version": "1.3.2",
433 | "source": {
434 | "type": "git",
435 | "url": "https://github.com/sebastianbergmann/environment.git",
436 | "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44"
437 | },
438 | "dist": {
439 | "type": "zip",
440 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6324c907ce7a52478eeeaede764f48733ef5ae44",
441 | "reference": "6324c907ce7a52478eeeaede764f48733ef5ae44",
442 | "shasum": ""
443 | },
444 | "require": {
445 | "php": ">=5.3.3"
446 | },
447 | "require-dev": {
448 | "phpunit/phpunit": "~4.4"
449 | },
450 | "type": "library",
451 | "extra": {
452 | "branch-alias": {
453 | "dev-master": "1.3.x-dev"
454 | }
455 | },
456 | "autoload": {
457 | "classmap": [
458 | "src/"
459 | ]
460 | },
461 | "notification-url": "https://packagist.org/downloads/",
462 | "license": [
463 | "BSD-3-Clause"
464 | ],
465 | "authors": [
466 | {
467 | "name": "Sebastian Bergmann",
468 | "email": "sebastian@phpunit.de"
469 | }
470 | ],
471 | "description": "Provides functionality to handle HHVM/PHP environments",
472 | "homepage": "http://www.github.com/sebastianbergmann/environment",
473 | "keywords": [
474 | "Xdebug",
475 | "environment",
476 | "hhvm"
477 | ],
478 | "time": "2015-08-03 06:14:51"
479 | },
480 | {
481 | "name": "sebastian/exporter",
482 | "version": "1.0.2",
483 | "source": {
484 | "type": "git",
485 | "url": "https://github.com/sebastianbergmann/exporter.git",
486 | "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0"
487 | },
488 | "dist": {
489 | "type": "zip",
490 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
491 | "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
492 | "shasum": ""
493 | },
494 | "require": {
495 | "php": ">=5.3.3"
496 | },
497 | "require-dev": {
498 | "phpunit/phpunit": "~4.0"
499 | },
500 | "type": "library",
501 | "extra": {
502 | "branch-alias": {
503 | "dev-master": "1.0.x-dev"
504 | }
505 | },
506 | "autoload": {
507 | "classmap": [
508 | "src/"
509 | ]
510 | },
511 | "notification-url": "https://packagist.org/downloads/",
512 | "license": [
513 | "BSD-3-Clause"
514 | ],
515 | "authors": [
516 | {
517 | "name": "Jeff Welch",
518 | "email": "whatthejeff@gmail.com"
519 | },
520 | {
521 | "name": "Volker Dusch",
522 | "email": "github@wallbash.com"
523 | },
524 | {
525 | "name": "Bernhard Schussek",
526 | "email": "bschussek@2bepublished.at"
527 | },
528 | {
529 | "name": "Sebastian Bergmann",
530 | "email": "sebastian@phpunit.de"
531 | },
532 | {
533 | "name": "Adam Harvey",
534 | "email": "aharvey@php.net"
535 | }
536 | ],
537 | "description": "Provides the functionality to export PHP variables for visualization",
538 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
539 | "keywords": [
540 | "export",
541 | "exporter"
542 | ],
543 | "time": "2014-09-10 00:51:36"
544 | },
545 | {
546 | "name": "sebastian/version",
547 | "version": "1.0.6",
548 | "source": {
549 | "type": "git",
550 | "url": "https://github.com/sebastianbergmann/version.git",
551 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
552 | },
553 | "dist": {
554 | "type": "zip",
555 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
556 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
557 | "shasum": ""
558 | },
559 | "type": "library",
560 | "autoload": {
561 | "classmap": [
562 | "src/"
563 | ]
564 | },
565 | "notification-url": "https://packagist.org/downloads/",
566 | "license": [
567 | "BSD-3-Clause"
568 | ],
569 | "authors": [
570 | {
571 | "name": "Sebastian Bergmann",
572 | "email": "sebastian@phpunit.de",
573 | "role": "lead"
574 | }
575 | ],
576 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
577 | "homepage": "https://github.com/sebastianbergmann/version",
578 | "time": "2015-06-21 13:59:46"
579 | },
580 | {
581 | "name": "symfony/yaml",
582 | "version": "v2.7.4",
583 | "source": {
584 | "type": "git",
585 | "url": "https://github.com/symfony/Yaml.git",
586 | "reference": "2dc7b06c065df96cc686c66da2705e5e18aef661"
587 | },
588 | "dist": {
589 | "type": "zip",
590 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/2dc7b06c065df96cc686c66da2705e5e18aef661",
591 | "reference": "2dc7b06c065df96cc686c66da2705e5e18aef661",
592 | "shasum": ""
593 | },
594 | "require": {
595 | "php": ">=5.3.9"
596 | },
597 | "require-dev": {
598 | "symfony/phpunit-bridge": "~2.7"
599 | },
600 | "type": "library",
601 | "extra": {
602 | "branch-alias": {
603 | "dev-master": "2.7-dev"
604 | }
605 | },
606 | "autoload": {
607 | "psr-4": {
608 | "Symfony\\Component\\Yaml\\": ""
609 | }
610 | },
611 | "notification-url": "https://packagist.org/downloads/",
612 | "license": [
613 | "MIT"
614 | ],
615 | "authors": [
616 | {
617 | "name": "Fabien Potencier",
618 | "email": "fabien@symfony.com"
619 | },
620 | {
621 | "name": "Symfony Community",
622 | "homepage": "https://symfony.com/contributors"
623 | }
624 | ],
625 | "description": "Symfony Yaml Component",
626 | "homepage": "https://symfony.com",
627 | "time": "2015-08-24 07:13:45"
628 | }
629 | ],
630 | "aliases": [],
631 | "minimum-stability": "stable",
632 | "stability-flags": [],
633 | "prefer-stable": false,
634 | "prefer-lowest": false,
635 | "platform": [],
636 | "platform-dev": []
637 | }
638 |
--------------------------------------------------------------------------------
/examples/callFunction.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set the timeout to be pretty short (in case your core is offline)
26 | $particle->setTimeout("5");
27 |
28 | // Set our access token (set in the phpConfig.config.php file)
29 | $particle->setAccessToken($accessToken);
30 |
31 | // Turn on the D7 LED (requires Tinker to be on your Particle Core)
32 | $particle->debug("Particle Function");
33 | if($particle->callFunction($deviceID, "digitalwrite", "D7,HIGH") == true)
34 | {
35 | $particle->debug_r($particle->getResult());
36 | }
37 | else
38 | {
39 | $particle->debug("Error: " . $particle->getError());
40 | $particle->debug("Error Source" . $particle->getErrorSource());
41 | }
42 | ?>
--------------------------------------------------------------------------------
/examples/claimDevice.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // claim a device on your account
29 | $particle->debug("Claim Device");
30 | if($particle->claimDevice($deviceID) == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/deleteDevice.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // Remove the device from your account
29 | $particle->debug("Remove Device");
30 | if($particle->deleteDevice($deviceID) == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/deleteToken.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Delete a specific token
26 | $token = "EXAMPLE_TOKEN";
27 | $particle->debug("Delete Token " . $token);
28 | $particle->setAuth($username, $password);
29 | if($particle->deleteToken($token) == true)
30 | {
31 | $particle->debug_r($particle->getResult());
32 | }
33 | else
34 | {
35 | $particle->debug("Error: " . $particle->getError());
36 | $particle->debug("Error Source" . $particle->getErrorSource());
37 | }
38 | ?>
--------------------------------------------------------------------------------
/examples/deleteWebhook.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | $webhookID = 'WEBHOOK_ID';
29 | // Delete particle webhook
30 | $particle->debug("Delete Particle Web Hook");
31 | if($particle->deleteWebhook($webhookID) == true)
32 | {
33 | $particle->debug_r($particle->getResult());
34 | }
35 | else
36 | {
37 | $particle->debug("Error: " . $particle->getError());
38 | $particle->debug("Error Source" . $particle->getErrorSource());
39 | }
40 | ?>
--------------------------------------------------------------------------------
/examples/getDeviceInfo.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // Grab a specific device's info
29 | $particle->debug("Particle Device Info");
30 | if($particle->getAttributes($deviceID) == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/getDeviceInfoInProduct.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // By setting the product slug all applicable operations become product-specific.
29 | $particle->setProductSlug($productSlug);
30 |
31 | // Grab a specific device's info
32 | $particle->debug("Particle Device Info");
33 | if($particle->getAttributes($deviceID) == true)
34 | {
35 | $particle->debug_r($particle->getResult());
36 | }
37 | else
38 | {
39 | $particle->debug("Error: " . $particle->getError());
40 | $particle->debug("Error Source" . $particle->getErrorSource());
41 | }
42 | ?>
--------------------------------------------------------------------------------
/examples/getToken.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Create Particle core token
26 | $particle->debug("generate Token");
27 | $particle->setAuth($username, $password);
28 | if($particle->createAccessToken() == true)
29 | {
30 | $particle->debug_r($particle->getResult());
31 | }
32 | else
33 | {
34 | $particle->debug("Error: " . $particle->getError());
35 | $particle->debug("Error Source" . $particle->getErrorSource());
36 | }
37 | ?>
--------------------------------------------------------------------------------
/examples/getVariable.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // Grab the current uptime of your core (requires a modified version of tinker on your Particle Core)
29 | $particle->debug("Particle Variable");
30 | if($particle->getVariable($deviceID, "uptime") == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/listDevices.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // List all the devices on your account
29 | $particle->debug("Particle Devices");
30 | if($particle->listDevices() == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/listDevicesInProduct.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // By setting the product slug all applicable operations become product-specific.
29 | $particle->setProductSlug($productSlug);
30 |
31 | // List all the devices on your account
32 | $particle->debug("Particle Devices");
33 | if($particle->listDevices() == true)
34 | {
35 | $particle->debug_r($particle->getResult());
36 | }
37 | else
38 | {
39 | $particle->debug("Error: " . $particle->getError());
40 | $particle->debug("Error Source" . $particle->getErrorSource());
41 | }
42 | ?>
--------------------------------------------------------------------------------
/examples/listTokens.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // List of Particle core tokens
26 | $particle->debug("Particle Tokens");
27 | $particle->setAuth($username, $password);
28 | if($particle->listAccessTokens() == true)
29 | {
30 | $particle->debug_r($particle->getResult());
31 | }
32 | else
33 | {
34 | $particle->debug("Error: " . $particle->getError());
35 | $particle->debug("Error Source" . $particle->getErrorSource());
36 | }
37 | ?>
--------------------------------------------------------------------------------
/examples/listWebhooks.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // List of Particle core tokens
29 | $particle->debug("Particle Web Hooks");
30 | if($particle->listWebhooks() == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/newAccessToken.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // List of Particle core tokens
26 | $particle->debug("New Access Token");
27 | $particle->setAuth($username, $password);
28 | if($particle->newAccessToken() == true)
29 | {
30 | $particle->debug_r($particle->getResult());
31 | }
32 | else
33 | {
34 | $particle->debug("Error: " . $particle->getError());
35 | $particle->debug("Error Source" . $particle->getErrorSource());
36 | }
37 | ?>
--------------------------------------------------------------------------------
/examples/newWebhook.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // create particle webhook
29 | $particle->debug("Create Particle Web Hook");
30 |
31 | $extras = array();
32 | $extras['mydevices'] = true;
33 | $extras['deviceid'] = $deviceID;
34 | $extras['requestType'] = "POST";
35 | //$extras['headers'] = array("X-Device-ID"=>"test");
36 | //$extras["form"] = json_encode(array("form_name"=>"form_value")); // Not implemented server side yet
37 | //$extras['json'] = array("json_key"=>"json_value");
38 | $extras['query'] = array("p1"=>"v1");
39 | $extras['auth'] = array("username"=>"test","password"=>"test_password");
40 |
41 | // headers & auth are mutually exclusive (can't have both at the same time or the call will fail on the cloud side)
42 | // json and query are mutually exclusive
43 |
44 | $fields = array_merge(array('event' => $event, 'url' => $url, 'deviceid' => $deviceID),$extras);
45 | print_r($fields);
46 |
47 | if($particle->newWebhook('test', 'http://google.com/',$extras) == true)
48 | {
49 | $particle->debug_r($particle->getResult());
50 | }
51 | else
52 | {
53 | $particle->debug("Error: " . $particle->getError());
54 | $particle->debug("Error Source" . $particle->getErrorSource());
55 | }
56 | ?>
--------------------------------------------------------------------------------
/examples/setDeviceName.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // Rename your Particle Core
29 | $particle->debug("Particle Set Device Name");
30 | if($particle->renameDevice($deviceID,uniqid('phpParticle_')) == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/signalDevice.php:
--------------------------------------------------------------------------------
1 | debug(...) by you ignore this line and display always
21 | $particle->setDebug(true);
22 | // Set the debug calls to display pretty HTML format. Other option is "TEXT". Note, calls made to $particle->debug(...) display as set here
23 | $particle->setDebugType("HTML");
24 |
25 | // Set our access token (set in the phpConfig.config.php file)
26 | $particle->setAccessToken($accessToken);
27 |
28 | // Signals the particle with a rainbow display using the rgb led
29 | $particle->debug("signal Particle Device");
30 | if($particle->signalDevice($deviceID,1) == true)
31 | {
32 | $particle->debug_r($particle->getResult());
33 | }
34 | else
35 | {
36 | $particle->debug("Error: " . $particle->getError());
37 | $particle->debug("Error Source" . $particle->getErrorSource());
38 | }
39 | ?>
--------------------------------------------------------------------------------
/examples/tinker.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harrisonhjones/phpParticle/26ca3270dac4b326961221c8d2de0e114b407dde/examples/tinker.bin
--------------------------------------------------------------------------------
/examples/tinker.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file application.cpp
4 | * @authors Satish Nair, Zachary Crockett and Mohit Bhoite
5 | * @version V1.0.0
6 | * @date 05-November-2013
7 | * @brief Tinker application
8 | ******************************************************************************
9 | Copyright (c) 2013 Particle Labs, Inc. All rights reserved.
10 |
11 | This program is free software; you can redistribute it and/or
12 | modify it under the terms of the GNU Lesser General Public
13 | License as published by the Free Software Foundation, either
14 | version 3 of the License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 | Lesser General Public License for more details.
20 |
21 | You should have received a copy of the GNU Lesser General Public
22 | License along with this program; if not, see
\n";
236 | return true;
237 | }
238 | else if($this->_debugType == "TEXT")
239 | {
240 | echo $debugText . "\n";
241 | return true;
242 | }
243 | else
244 | {
245 | $this->_setError("Bad debut type (" . $this->_debugType . ")", "_debug");
246 | return false;
247 | }
248 | }
249 | }
250 |
251 | /**
252 | * Private Function. Outputs the desired debug array formatted if required
253 | *
254 | * @param mixed[] $debugArray The debug array to output
255 | * @param string $override If set to true overrides the internal debug on/off state and always outputs the debugArray. If set to false it follows the internal debug on/off state
256 | *
257 | * @return void
258 | *
259 | */
260 | private function _debug_r($debugArray, $override = false)
261 | {
262 | if(($this->_debug == true) || ($override == true))
263 | {
264 | if($this->_debugType == "HTML")
265 | {
266 | $this->debug("
"); 267 | print_r($debugArray); 268 | $this->debug(""); 269 | return true; 270 | } 271 | else if($this->_debugType == "TEXT") 272 | { 273 | print_r($debugArray); 274 | $this->debug(); 275 | return true; 276 | } 277 | else 278 | { 279 | $this->_setError("Bad debut type (" . $this->_debugType . ")", "_debug"); 280 | return false; 281 | } 282 | } 283 | } 284 | 285 | /** 286 | * Outputs the desired debug text formatted if required 287 | * 288 | * @param string $debugText The debug string to output 289 | * 290 | * @return void 291 | * 292 | */ 293 | public function debug($debugText) 294 | { 295 | return $this->_debug($debugText, $override = true); 296 | } 297 | 298 | /** 299 | * Outputs the desired debug array formatted if required 300 | * 301 | * @param string $debugArray The debug array to output 302 | * 303 | * @return void 304 | * 305 | */ 306 | public function debug_r($debugArray) 307 | { 308 | return $this->_debug_r($debugArray, $override = true); 309 | } 310 | 311 | /** 312 | * Runs a particle function on the device. Requires the accessToken to be set 313 | * 314 | * @param string $deviceID The device ID of the device to call the function on 315 | * @param string $deviceFunction The name function to call 316 | * @param string $params The parameters to send to the function (the 'args') 317 | * 318 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 319 | */ 320 | public function callFunction($deviceID, $deviceFunction, $params) 321 | { 322 | if(empty($this->_productSlug)) { 323 | $url = $this->_endpoint . 'v1/devices/' . $deviceID . '/' . $deviceFunction; 324 | } else { 325 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID . '/' . $deviceFunction; 326 | } 327 | return $this->_curlRequest($url, array('args'=>$params), 'post'); 328 | } 329 | 330 | /** 331 | * Gets the value of a particle variable. Requires the accessToken to be set 332 | * 333 | * @param string $deviceID The device ID of the device to call the function on 334 | * @param string $variableName The name of the variable to retrieve 335 | * 336 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 337 | */ 338 | public function getVariable($deviceID, $variableName) 339 | { 340 | if(empty($this->_productSlug)) { 341 | $url = $this->_endpoint . 'v1/devices/' . $deviceID . '/' . $variableName; 342 | } else { 343 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID . '/' . $variableName; 344 | } 345 | return $this->_curlRequest($url, array(), 'get'); 346 | } 347 | 348 | /** 349 | * Lists all your cores assigned to your cloud account. Requires the accessToken to be set 350 | * 351 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 352 | */ 353 | public function listDevices() 354 | { 355 | if(empty($this->_productSlug)) { 356 | $url = $this->_endpoint . 'v1/devices/'; 357 | return $this->_curlRequest($url, array(), 'get'); 358 | } else { 359 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/'; 360 | return $this->_curlRequest($url, array(), 'get', 'none', 'devices'); 361 | } 362 | } 363 | /** 364 | * Gets your details from your core e.g. function and variables. Requires the accessToken to be set 365 | * 366 | * @param string $deviceID The device ID of the device 367 | * 368 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 369 | */ 370 | public function getAttributes($deviceID) 371 | { 372 | if(empty($this->_productSlug)) { 373 | $url = $this->_endpoint . 'v1/devices/' . $deviceID; 374 | } else { 375 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID; 376 | } 377 | return $this->_curlRequest($url, array(), 'get'); 378 | } 379 | 380 | /** 381 | * Set the name/renames your core. Requires the accessToken to be set 382 | * 383 | * @param string $deviceID The device ID of the device to rename 384 | * @param string $name The new name of the device 385 | * 386 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 387 | */ 388 | public function renameCore($deviceID,$name) 389 | { 390 | if(empty($this->_productSlug)) { 391 | $url = $this->_endpoint . 'v1/devices/' . $deviceID; 392 | } else { 393 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID; 394 | } 395 | return $this->_curlRequest($url, array("name" => $name), 'put'); 396 | } 397 | 398 | /** 399 | * Attempts to add a device to your cloud account. Requires the accessToken to be set. Note, you may want to follow this up with a call to "setName" as new Core's names are blank. Interestingly, if claiming an order core their name is retained across the unclaim/claim process 400 | * 401 | * @param string $deviceID The device ID of the device to claim. 402 | * @param boolean $requestTransfer If true requests that the device be transfered to your account (use if the device is already claimed). If false will try to claim but not automatically send a transfer request 403 | * 404 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 405 | */ 406 | 407 | public function claimDevice($deviceID, $requestTransfer = false) 408 | { 409 | if(empty($this->_productSlug)) { 410 | $url = $this->_endpoint . 'v1/devices'; 411 | } else { 412 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices'; 413 | } 414 | if($requestTransfer) 415 | $result = $this->_curlRequest($url, array('id' => $deviceID, 'request_transfer' => 'true'), 'post'); 416 | else 417 | $result = $this->_curlRequest($url, array('id' => $deviceID, 'request_transfer' => 'false'), 'post'); 418 | 419 | return $result; 420 | } 421 | 422 | /** 423 | * Removes the core from your cloud account. Requires the accessToken to be set 424 | * 425 | * @param string $deviceID The device ID of the device to remove from your account. 426 | * 427 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 428 | */ 429 | public function removeDevice($deviceID) 430 | { 431 | if(empty($this->_productSlug)) { 432 | $url = $this->_endpoint . 'v1/devices/' . $deviceID; 433 | } else { 434 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID; 435 | } 436 | return $this->_curlRequest($url, array(), 'delete'); 437 | } 438 | 439 | /** 440 | * Uploads a sketch to the core. Requires the accessToken to be set 441 | * 442 | * @param string $deviceID The device ID of the device to upload the code to 443 | * @param string $filename The filename of the firmware file to upload to the device. Ex: tinker.cpp. Not yet implemented 444 | * @param string $filepath The path to the firmware file to upload (including the name). Ex: path/to/tinker.cpp 445 | * @param boolean $isBinary Set to true if uploading a .bin file or false otherwise. 446 | * 447 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 448 | */ 449 | public function uploadFirmware($deviceID,$filename,$filepath,$isBinary=false) 450 | { 451 | if(empty($this->_productSlug)) { 452 | $url = $this->_endpoint . 'v1/devices/' . $deviceID; 453 | } else { 454 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID; 455 | } 456 | // Create a CURLFile object 457 | $cfile = new CURLFile($filepath,'application/octet-stream',$filename); 458 | $params = array('file' => $cfile); 459 | if($isBinary == true) 460 | $params['file_type'] = "binary"; 461 | return $this->_curlRequest($url, $params, 'put-file'); 462 | } 463 | 464 | /** 465 | * Gets a list of your tokens from the particle cloud. Requires the email/password auth to be set 466 | * 467 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 468 | */ 469 | public function listAccessTokens() 470 | { 471 | $url = $this->_endpoint .'v1/access_tokens'; 472 | $result = $this->_curlRequest($url, array(), 'get', 'basic'); 473 | 474 | return $result; 475 | } 476 | 477 | /** 478 | * Creates a new token on the particle cloud. Requires the email/password auth to be set 479 | * 480 | * @param int $expires_in When the token should expire (in seconds). Set to false to ignore and use the default. Set to 0 for a token that never expires 481 | * @param string $expires_at When the token should expire (at a date/time). Set to false to ignore and use the default. Set to 'null' for a token that never expires. Otherwise this should be a ISO8601 style date string 482 | * @param string $clientID The clientID. If you don't have one of these (only used in OAuth applications) set to false 483 | * @param string $clientSecret The clientSecret. If you don't have one of these (only used in OAuth applications) set to false 484 | * 485 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 486 | */ 487 | 488 | public function newAccessToken($expires_in = false, $expires_at = false, $clientID = false, $clientSecret = false) 489 | { 490 | $fields = array('grant_type' => 'password', 'username' => $this->_email, 'password' => $this->_password); 491 | 492 | if($expires_in !== false) 493 | $fields['expires_in'] = intval($expires_in); 494 | 495 | if($expires_at !== false) 496 | $fields['expires_at'] = $expires_at; 497 | 498 | if($clientID) 499 | { 500 | $fields['client_id'] = $clientID; 501 | $fields['client_secret'] = $clientSecret; 502 | } 503 | 504 | $url = $this->_endpoint .'oauth/token'; 505 | $result = $this->_curlRequest($url, $fields, 'post', 'basic-dummy'); 506 | 507 | return $result; 508 | } 509 | 510 | /** 511 | * Removes the token from the particle cloud. Requires the email/password auth to be set 512 | * 513 | * @param string $token The access token to remove 514 | * 515 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 516 | */ 517 | public function deleteAccessToken($token) 518 | { 519 | $url = $this->_endpoint .'v1/access_tokens/'.$token; 520 | $result = $this->_curlRequest($url, array(), 'delete', 'basic'); 521 | 522 | return $result; 523 | } 524 | 525 | /** 526 | * Gets a list of webhooks from the particle cloud. Requires the accessToken to be set 527 | * 528 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 529 | */ 530 | public function listWebhooks() 531 | { 532 | $fields = array(); 533 | $url = $this->_endpoint .'v1/webhooks'; 534 | $result = $this->_curlRequest($url, $fields, 'get'); 535 | 536 | return $result; 537 | } 538 | 539 | /** 540 | * Creates a new webhook on the particle cloud. Requires the accessToken to be set 541 | * @param string $event The event name used to trigger the webhook 542 | * @param string $webhookUrl The url to query once the event has occured 543 | * @param string $extras See http://docs.particle.io/webhooks/#webhook-options 544 | * 545 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 546 | */ 547 | public function newWebhook($event, $webhookUrl, $extras = array()) 548 | { 549 | $url = $this->_endpoint .'v1/webhooks/'; 550 | 551 | $fields = array_merge(array('event' => $event, 'url' => $webhookUrl),$extras); 552 | 553 | $result = $this->_curlRequest($url, $fields , 'post'); 554 | 555 | return $result; 556 | } 557 | 558 | /** 559 | * Delete webhooks from the particle cloud. Requires the accessToken to be set 560 | * 561 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 562 | */ 563 | public function deleteWebhook($webhookID) 564 | { 565 | $fields = array(); 566 | $url = $this->_endpoint ."v1/webhooks/{$webhookID}/"; 567 | $result = $this->_curlRequest($url, $fields, 'delete'); 568 | 569 | return $result; 570 | } 571 | 572 | /** 573 | * Sets the particle core signal mode state. Requires the accessToken to be set 574 | * 575 | * @param string $deviceID The device ID of the device to send the signal mode state change command to. 576 | * @param int $signalState The signal state: 0 returns the RGB led back to normmal & 1 makes it flash a rainbow of color 577 | * 578 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 579 | */ 580 | public function signalDevice($deviceID, $signalState = 0) 581 | { 582 | if(empty($this->_productSlug)) { 583 | $url = $this->_endpoint . 'v1/devices/' . $deviceID; 584 | } else { 585 | $url = $this->_endpoint . 'v1/products/' . $this->_productSlug . '/devices/' . $deviceID; 586 | } 587 | $fields = array('signal' => $signalState); 588 | return $this->_curlRequest($url, $fields, 'put'); 589 | } 590 | 591 | /** 592 | * Returns the latest error 593 | * 594 | * @return string The latest error 595 | */ 596 | public function getError() 597 | { 598 | return $this->_error; 599 | } 600 | 601 | /** 602 | * Returns the latest error's source (which function cause the error) 603 | * 604 | * @return string The latest error's source 605 | */ 606 | public function getErrorSource() 607 | { 608 | return $this->_errorSource; 609 | } 610 | 611 | /** 612 | * Returns the latest result 613 | * 614 | * @return string The latest result from calling a cloud function 615 | */ 616 | public function getResult() 617 | { 618 | return $this->_result; 619 | } 620 | 621 | /** 622 | * Private Function. Performs a CURL Request with the given parameters 623 | * 624 | * @param string url The url to call 625 | * @param mixed[] params An array of parameters to pass to the url 626 | * @param string type The type of request ("GET", "POST", "PUT", etc) 627 | * @param string authType The type of authorization to use ('none' uses the access token, 'basic' uses basic auth with the email/password auth details, and 'basic-dummy' uses dummy basic auth details) 628 | * 629 | * @return boolean true on success, false on failure 630 | */ 631 | private function _curlRequest($url, $params = null, $type = 'post', $authType = 'none', $key = false) 632 | { 633 | 634 | $fields_string = null; 635 | 636 | if($authType == 'none') 637 | if ($this->_accessToken) 638 | { 639 | $params['access_token'] = $this->_accessToken; 640 | } 641 | else 642 | { 643 | $errorText = "No access token set"; 644 | list(, $caller) = debug_backtrace(false); 645 | $this->_setError($errorText, $caller['function']); 646 | return false; 647 | } 648 | 649 | 650 | // is cURL installed yet? 651 | if (!function_exists('curl_init')) 652 | { 653 | die("CURL is not installed/available"); 654 | } 655 | 656 | // OK cool - then let's create a new cURL resource handle 657 | $ch = curl_init(); 658 | //set the number of POST vars, POST data 659 | if($type == 'get') 660 | { 661 | $url .= ("?" . http_build_query($params)); 662 | } 663 | else if ($type == 'post') 664 | { 665 | curl_setopt($ch,CURLOPT_POST,count($params)); 666 | curl_setopt($ch,CURLOPT_POSTFIELDS,http_build_query($params)); 667 | } 668 | else if($type == "put") 669 | { 670 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); 671 | curl_setopt($ch,CURLOPT_POSTFIELDS,http_build_query($params)); 672 | } 673 | else if($type == "put-file") 674 | { 675 | curl_setopt($ch, CURLOPT_POST, true); 676 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); 677 | unset($params['access_token']); 678 | curl_setopt($ch,CURLOPT_POSTFIELDS,$params); 679 | $url .= "?access_token=" . $this->_accessToken; 680 | } 681 | else if ($type == 'delete') 682 | { 683 | $url .= ("?" . http_build_query($params)); 684 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); 685 | } 686 | else 687 | { 688 | $errorText = "Unsupported method type (" . $type . ")"; 689 | $this->_setError($errorText, __FUNCTION__); 690 | return false; 691 | } 692 | 693 | $this->_debug("Opening a {$type} connection to {$url}"); 694 | curl_setopt($ch, CURLOPT_URL, $url); 695 | 696 | if($this->_disableSSL) 697 | { 698 | // stop the verification of certificate 699 | $this->_debug("[WARN] Disabling SSL Verification for CURL"); 700 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 701 | } 702 | 703 | // Set a referer 704 | // curl_setopt($ch, CURLOPT_REFERER, "http://www.example.com/curl.htm"); 705 | 706 | // User agent 707 | // curl_setopt($ch, CURLOPT_USERAGENT, "MozillaXYZ/1.0"); 708 | 709 | // Include header in result? (0 = yes, 1 = no) 710 | curl_setopt($ch, CURLOPT_HEADER, 0); 711 | 712 | // Should cURL return or print out the data? (true = return, false = print) 713 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 714 | 715 | // Timeout in seconds 716 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->_curlTimeout); 717 | 718 | $this->_debug("Auth Type: " . $authType); 719 | // basic auth 720 | if ($authType == 'basic') { 721 | if(($this->_email) && ($this->_password)) 722 | { 723 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 724 | curl_setopt($ch, CURLOPT_USERPWD, $this->_email . ":" . $this->_password); 725 | } 726 | else 727 | { 728 | list(, $caller) = debug_backtrace(false); 729 | $errorText = "No auth credentials (email/password) set"; 730 | $this->_setError($errorText, $caller['function']); 731 | return false; 732 | } 733 | } 734 | if ($authType == 'basic-dummy') { 735 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 736 | curl_setopt($ch, CURLOPT_USERPWD, "particle:particle"); 737 | } 738 | 739 | // Download the given URL, and return output 740 | $this->_debug("Executing Curl Operation"); 741 | $this->_debug("Url:"); 742 | $this->_debug_r($url); 743 | $this->_debug("Params:"); 744 | $this->_debug_r($params); 745 | $output = curl_exec($ch); 746 | 747 | $this->_debug("Curl Result: '" . $output . "'"); 748 | 749 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 750 | $this->_debug("Curl Response Code: '" . $httpCode."'"); 751 | // Close the cURL resource, and free system resources 752 | 753 | $curlError = curl_errno($ch); 754 | curl_close($ch); 755 | if($curlError != CURLE_OK) 756 | { 757 | $this->_debug("CURL Request - There was a CURL error"); 758 | list(, $caller) = debug_backtrace(false); 759 | //var_dump($caller['function']); 760 | $errorText = $this->_curlErrorCode($curlError); 761 | $this->_setError($errorText, $caller['function']); 762 | return false; 763 | } 764 | else 765 | { 766 | $retVal = json_decode($output,true); 767 | 768 | if(json_last_error() == 0) 769 | { 770 | if(isset($retVal['error']) && $retVal['error']) 771 | { 772 | $this->_debug("CURL Request - API response contained 'error' field"); 773 | $errorText = $retVal['error']; 774 | $this->_setError($errorText, __FUNCTION__); 775 | return false; 776 | } 777 | else 778 | { 779 | $this->_debug("CURL Request - Returning True"); 780 | if($key != false) { 781 | $this->_debug("CURL Request - Extracting from key '" . $key . "'"); 782 | $this->_result = $retVal[$key]; 783 | } else { 784 | $this->_result = $retVal; 785 | } 786 | 787 | return true; 788 | } 789 | } 790 | else 791 | { 792 | $this->_debug("CURL Request - Unable to parse JSON"); 793 | $errorText = "Unable to parse JSON. Json error = " . json_last_error() . ". See http://php.net/manual/en/function.json-last-error.php for more information. Raw response from Particle Cloud = '" . $result . "'"; 794 | $this->_setError($errorText, __FUNCTION__); 795 | return false; 796 | } 797 | } 798 | } 799 | 800 | /** 801 | * Private Function. Returns a human readable string for a given CURL Error Code 802 | * 803 | * @param int curlCode The CURL error code 804 | * 805 | * @return string A human-readable string version of the curlCode 806 | */ 807 | private function _curlErrorCode($curlCode) 808 | { 809 | switch ($curlCode) 810 | { 811 | case 26: 812 | return "Curl Error. There was a problem reading a local file or an error returned by the read callback."; 813 | case 30: 814 | return "Curl Error. Operation timeout. The specified time-out period was reached according to the conditions."; 815 | default: 816 | return "Curl Error. Error number = {$curlCode}. See http://curl.haxx.se/libcurl/c/libcurl-errors.html for more information"; 817 | } 818 | } 819 | } -------------------------------------------------------------------------------- /phpParticle.config.sample.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phpParticle.firmware.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file application.cpp 4 | * @authors Satish Nair, Zachary Crockett and Mohit Bhoite 5 | * @version V1.0.0 6 | * @date 05-November-2013 7 | * @brief Tinker application 8 | ****************************************************************************** 9 | Copyright (c) 2013 Particle Labs, Inc. All rights reserved. 10 | 11 | This program is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU Lesser General Public 13 | License as published by the Free Software Foundation, either 14 | version 3 of the License, or (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | Lesser General Public License for more details. 20 | 21 | You should have received a copy of the GNU Lesser General Public 22 | License along with this program; if not, see
"); 337 | print_r($debugArray); 338 | $this->debug(""); 339 | return true; 340 | } 341 | else if($this->_debugType == "TEXT") 342 | { 343 | print_r($debugArray); 344 | $this->debug(); 345 | return true; 346 | } 347 | else 348 | { 349 | $this->_setError("Bad debut type (" . $this->_debugType . ")", "_debug"); 350 | return false; 351 | } 352 | } 353 | } 354 | 355 | /** 356 | * Outputs the desired debug text formatted if required 357 | * 358 | * @param string $debugText The debug string to output 359 | * 360 | * @return void 361 | * 362 | */ 363 | public function debug($debugText) 364 | { 365 | return $this->_debug($debugText, $override = true); 366 | } 367 | 368 | /** 369 | * Outputs the desired debug array formatted if required 370 | * 371 | * @param string $debugArray The debug array to output 372 | * 373 | * @return void 374 | * 375 | */ 376 | public function debug_r($debugArray) 377 | { 378 | return $this->_debug_r($debugArray, $override = true); 379 | } 380 | 381 | /** 382 | * Runs a particle function on the device. Requires the accessToken to be set 383 | * 384 | * @param string $deviceID The device ID of the device to call the function on 385 | * @param string $deviceFunction The name function to call 386 | * @param string $params The parameters to send to the function (the 'args') 387 | * 388 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 389 | */ 390 | public function callFunction($deviceID, $deviceFunction, $params) 391 | { 392 | $url = $this->_endpoint .'v1/'; 393 | if(empty($this->_productSlug)) { 394 | $url .= 'devices/' . $deviceID . '/' . $deviceFunction; 395 | } else { 396 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID . '/' . $deviceFunction; 397 | } 398 | return $this->_curlRequest($url, array('args'=>$params), 'post'); 399 | } 400 | 401 | /** 402 | * Gets the value of a particle variable. Requires the accessToken to be set 403 | * 404 | * @param string $deviceID The device ID of the device to call the function on 405 | * @param string $variableName The name of the variable to retrieve 406 | * 407 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 408 | */ 409 | public function getVariable($deviceID, $variableName) 410 | { 411 | $url = $this->_endpoint .'v1/'; 412 | if(empty($this->_productSlug)) { 413 | $url .= 'devices/' . $deviceID . '/' . $variableName; 414 | } else { 415 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID . '/' . $variableName; 416 | } 417 | return $this->_curlRequest($url, array(), 'get'); 418 | } 419 | 420 | /** 421 | * Lists all your cores assigned to your cloud account. Requires the accessToken to be set 422 | * 423 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 424 | */ 425 | public function listDevices() 426 | { 427 | $url = $this->_endpoint .'v1/'; 428 | if(empty($this->_productSlug)) { 429 | $url .= 'devices/'; 430 | } else { 431 | $url .= 'products/' . $this->_productSlug . '/devices/'; 432 | } 433 | return $this->_curlRequest($url, array(), 'get'); 434 | } 435 | 436 | /** 437 | * Gets your details from your core e.g. function and variables. Requires the accessToken to be set 438 | * 439 | * @param string $deviceID The device ID of the device 440 | * 441 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 442 | */ 443 | public function getAttributes($deviceID) 444 | { 445 | $url = $this->_endpoint .'v1/'; 446 | if(empty($this->_productSlug)) { 447 | $url .= 'devices/' . $deviceID; 448 | } else { 449 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID; 450 | } 451 | return $this->_curlRequest($url, array(), 'get'); 452 | } 453 | 454 | /** 455 | * Set the name/renames your core. Requires the accessToken to be set 456 | * 457 | * @param string $deviceID The device ID of the device to rename 458 | * @param string $name The new name of the device 459 | * 460 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 461 | */ 462 | public function renameDevice($deviceID,$name) 463 | { 464 | $url = $this->_endpoint .'v1/'; 465 | if(empty($this->_productSlug)) { 466 | $url .= 'devices/' . $deviceID; 467 | } else { 468 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID; 469 | } 470 | return $this->_curlRequest($url, array("name" => $name), 'put'); 471 | } 472 | 473 | /** 474 | * Attempts to add a device to your cloud account. Requires the accessToken to be set. Note, you may want to follow this up with a call to "setName" as new Core's names are blank. Interestingly, if claiming an order core their name is retained across the unclaim/claim process 475 | * 476 | * @param string $deviceID The device ID of the device to claim. 477 | * @param boolean $requestTransfer If true requests that the device be transfered to your account (use if the device is already claimed). If false will try to claim but not automatically send a transfer request 478 | * 479 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 480 | */ 481 | 482 | public function claimDevice($deviceID, $requestTransfer = false) 483 | { 484 | $url = $this->_endpoint .'v1/'; 485 | if(empty($this->_productSlug)) { 486 | $url .= 'devices'; 487 | } else { 488 | $url .= 'products/' . $this->_productSlug . '/devices'; 489 | } 490 | if($requestTransfer) 491 | $result = $this->_curlRequest($url, array('id' => $deviceID, 'request_transfer' => 'true'), 'post'); 492 | else 493 | $result = $this->_curlRequest($url, array('id' => $deviceID, 'request_transfer' => 'false'), 'post'); 494 | 495 | return $result; 496 | } 497 | 498 | /** 499 | * Removes the core from your cloud account. Requires the accessToken to be set 500 | * 501 | * @param string $deviceID The device ID of the device to remove from your account. 502 | * 503 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 504 | */ 505 | public function removeDevice($deviceID) 506 | { 507 | $url = $this->_endpoint .'v1/'; 508 | if(empty($this->_productSlug)) { 509 | $url .= 'devices/' . $deviceID; 510 | } else { 511 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID; 512 | } 513 | return $this->_curlRequest($url, array(), 'delete'); 514 | } 515 | 516 | /** 517 | * Uploads a sketch to a Particle device. Requires the accessToken to be set 518 | * 519 | * @param string $deviceID The device ID of the device to upload the code to 520 | * @param string $filename The filename of the firmware file to upload to the device. Ex: tinker.cpp. Not yet implemented 521 | * @param string $filepath The path to the firmware file to upload (including the name). Ex: path/to/tinker.cpp 522 | * @param boolean $isBinary Set to true if uploading a .bin file or false otherwise. 523 | * 524 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 525 | */ 526 | public function uploadFirmware($deviceID,$filename,$filepath,$isBinary=false) 527 | { 528 | // Create a CURLFile object 529 | $cfile = new CURLFile($filepath,'application/octet-stream',$filename); 530 | 531 | $url = $this->_endpoint .'v1/'; 532 | if(empty($this->_productSlug)) { 533 | $url .= 'devices/' . $deviceID; 534 | } else { 535 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID; 536 | } 537 | 538 | $params = array('file' => $cfile); 539 | if($isBinary == true) 540 | $params['file_type'] = "binary"; 541 | $result = $this->_curlRequest($url, $params, 'put-file'); 542 | return $result; 543 | } 544 | 545 | /** 546 | * Gets a list of your tokens from the particle cloud. Requires the email/password auth to be set 547 | * 548 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 549 | */ 550 | public function listAccessTokens() 551 | { 552 | $url = $this->_endpoint .'v1/access_tokens'; 553 | return $this->_curlRequest($url, array(), 'get', 'basic'); 554 | } 555 | 556 | /** 557 | * Creates a new token on the particle cloud. Requires the email/password auth to be set 558 | * 559 | * @param int $expires_in When the token should expire (in seconds). Set to false to ignore and use the default. Set to 0 for a token that never expires 560 | * @param string $expires_at When the token should expire (at a date/time). Set to false to ignore and use the default. Set to 'null' for a token that never expires. Otherwise this should be a ISO8601 style date string 561 | * @param string $clientID The clientID. If you don't have one of these (only used in OAuth applications) set to false 562 | * @param string $clientSecret The clientSecret. If you don't have one of these (only used in OAuth applications) set to false 563 | * 564 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 565 | */ 566 | 567 | public function newAccessToken($expires_in = false, $expires_at = false, $clientID = false, $clientSecret = false) 568 | { 569 | $fields = array('grant_type' => 'password', 'username' => $this->_email, 'password' => $this->_password); 570 | 571 | if($expires_in !== false) 572 | $fields['expires_in'] = intval($expires_in); 573 | 574 | if($expires_at !== false) 575 | $fields['expires_at'] = $expires_at; 576 | 577 | if($clientID) 578 | { 579 | $fields['client_id'] = $clientID; 580 | $fields['client_secret'] = $clientSecret; 581 | } 582 | 583 | $url = $this->_endpoint .'oauth/token'; 584 | $result = $this->_curlRequest($url, $fields, 'post', 'basic-dummy'); 585 | 586 | return $result; 587 | } 588 | 589 | /** 590 | * Removes the token from the particle cloud. Requires the email/password auth to be set 591 | * 592 | * @param string $token The access token to remove 593 | * 594 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 595 | */ 596 | public function deleteAccessToken($token) 597 | { 598 | $url = $this->_endpoint .'v1/access_tokens/'.$token; 599 | $result = $this->_curlRequest($url, array(), 'delete', 'basic'); 600 | 601 | return $result; 602 | } 603 | 604 | /** 605 | * Gets a list of webhooks from the particle cloud. Requires the accessToken to be set 606 | * 607 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 608 | */ 609 | public function listWebhooks() 610 | { 611 | $fields = array(); 612 | $url = $this->_endpoint .'v1/webhooks'; 613 | $result = $this->_curlRequest($url, $fields, 'get'); 614 | 615 | return $result; 616 | } 617 | 618 | /** 619 | * Creates a new webhook on the particle cloud. Requires the accessToken to be set 620 | * @param string $event The event name used to trigger the webhook 621 | * @param string $webhookUrl The url to query once the event has occured 622 | * @param string $extras See http://docs.particle.io/webhooks/#webhook-options 623 | * 624 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 625 | */ 626 | public function newWebhook($event, $webhookUrl, $extras = array()) 627 | { 628 | $url = $this->_endpoint .'v1/webhooks/'; 629 | $fields = array_merge(array('event' => $event, 'url' => $webhookUrl),$extras); 630 | $result = $this->_curlRequest($url, $fields , 'post'); 631 | return $result; 632 | } 633 | 634 | /** 635 | * Delete webhooks from the particle cloud. Requires the accessToken to be set 636 | * 637 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 638 | */ 639 | public function deleteWebhook($webhookID) 640 | { 641 | $fields = array(); 642 | $url = $this->_endpoint ."v1/webhooks/{$webhookID}/"; 643 | $result = $this->_curlRequest($url, $fields, 'delete'); 644 | 645 | return $result; 646 | } 647 | 648 | /** 649 | * Sets the particle core signal mode state. Requires the accessToken to be set 650 | * 651 | * @param string $deviceID The device ID of the device to send the signal mode state change command to. 652 | * @param int $signalState The signal state: 0 returns the RGB led back to normmal & 1 makes it flash a rainbow of color 653 | * 654 | * @return boolean true if the call was successful, false otherwise. Use getResult to get the api result and use getError & getErrorSource to determine what happened in the event of an error 655 | */ 656 | public function signalDevice($deviceID, $signalState = 0) 657 | { 658 | $url = $this->_endpoint .'v1/'; 659 | if(empty($this->_productSlug)) { 660 | $url .= 'devices/' . $deviceID; 661 | } else { 662 | $url .= 'products/' . $this->_productSlug . '/devices/' . $deviceID; 663 | } 664 | $fields = array('signal' => $signalState); 665 | //$url = $this->_endpoint ."v1/devices/{$deviceID}/"; 666 | return $this->_curlRequest($url, $fields, 'put'); 667 | } 668 | 669 | /** 670 | * Returns the latest error 671 | * 672 | * @return string The latest error 673 | */ 674 | public function getError() 675 | { 676 | return $this->_error; 677 | } 678 | 679 | /** 680 | * Returns the latest error's source (which function cause the error) 681 | * 682 | * @return string The latest error's source 683 | */ 684 | public function getErrorSource() 685 | { 686 | return $this->_errorSource; 687 | } 688 | 689 | /** 690 | * Returns the latest result 691 | * 692 | * @return string The latest result from calling a cloud function 693 | */ 694 | public function getResult() 695 | { 696 | return $this->_result; 697 | } 698 | 699 | /** 700 | * Private Function. Performs a CURL Request with the given parameters 701 | * 702 | * @param string url The url to call 703 | * @param mixed[] params An array of parameters to pass to the url 704 | * @param string type The type of request ("GET", "POST", "PUT", etc) 705 | * @param string authType The type of authorization to use ('none' uses the access token, 'basic' uses basic auth with the email/password auth details, and 'basic-dummy' uses dummy basic auth details) 706 | * 707 | * @return boolean true on success, false on failure 708 | */ 709 | private function _curlRequest($url, $params = null, $type = 'post', $authType = 'none') 710 | { 711 | 712 | $fields_string = null; 713 | 714 | if($authType == 'none') 715 | if ($this->_accessToken) 716 | { 717 | $params['access_token'] = $this->_accessToken; 718 | } 719 | else 720 | { 721 | $errorText = "No access token set"; 722 | list(, $caller) = debug_backtrace(false); 723 | $this->_setError($errorText, $caller['function']); 724 | return false; 725 | } 726 | 727 | 728 | // is cURL installed yet? 729 | if (!function_exists('curl_init')) 730 | { 731 | die("CURL is not installed/available"); 732 | } 733 | 734 | // OK cool - then let's create a new cURL resource handle 735 | $ch = curl_init(); 736 | //set the number of POST vars, POST data 737 | if($type == 'get') 738 | { 739 | $url .= ("?" . http_build_query($params)); 740 | } 741 | else if ($type == 'post') 742 | { 743 | curl_setopt($ch,CURLOPT_POST,count($params)); 744 | curl_setopt($ch,CURLOPT_POSTFIELDS,http_build_query($params)); 745 | } 746 | else if($type == "put") 747 | { 748 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); 749 | curl_setopt($ch,CURLOPT_POSTFIELDS,http_build_query($params)); 750 | } 751 | else if($type == "put-file") 752 | { 753 | curl_setopt($ch, CURLOPT_POST, true); 754 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); 755 | unset($params['access_token']); 756 | curl_setopt($ch,CURLOPT_POSTFIELDS,$params); 757 | $url .= "?access_token=" . $this->_accessToken; 758 | } 759 | else if ($type == 'delete') 760 | { 761 | $url .= ("?" . http_build_query($params)); 762 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); 763 | } 764 | else 765 | { 766 | $errorText = "Unsupported method type (" . $type . ")"; 767 | $this->_setError($errorText, __FUNCTION__); 768 | return false; 769 | } 770 | 771 | $this->_debug("Opening a {$type} connection to {$url}"); 772 | curl_setopt($ch, CURLOPT_URL, $url); 773 | 774 | if($this->_disableSSL) 775 | { 776 | // stop the verification of certificate 777 | $this->_debug("[WARN] Disabling SSL Verification for CURL"); 778 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 779 | } 780 | 781 | // Set a referer 782 | // curl_setopt($ch, CURLOPT_REFERER, "http://www.example.com/curl.htm"); 783 | 784 | // User agent 785 | // curl_setopt($ch, CURLOPT_USERAGENT, "MozillaXYZ/1.0"); 786 | 787 | // Include header in result? (0 = yes, 1 = no) 788 | curl_setopt($ch, CURLOPT_HEADER, 0); 789 | 790 | // Should cURL return or print out the data? (true = return, false = print) 791 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 792 | 793 | // Timeout in seconds 794 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->_curlTimeout); 795 | 796 | $this->_debug("Auth Type: " . $authType); 797 | // basic auth 798 | if ($authType == 'basic') { 799 | if(($this->_email) && ($this->_password)) 800 | { 801 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 802 | curl_setopt($ch, CURLOPT_USERPWD, $this->_email . ":" . $this->_password); 803 | } 804 | else 805 | { 806 | list(, $caller) = debug_backtrace(false); 807 | $errorText = "No auth credentials (email/password) set"; 808 | $this->_setError($errorText, $caller['function']); 809 | return false; 810 | } 811 | } 812 | if ($authType == 'basic-dummy') { 813 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 814 | curl_setopt($ch, CURLOPT_USERPWD, "particle:particle"); 815 | } 816 | 817 | // Download the given URL, and return output 818 | $this->_debug("Executing Curl Operation"); 819 | $this->_debug("Url:"); 820 | $this->_debug_r($url); 821 | $this->_debug("Params:"); 822 | $this->_debug_r($params); 823 | $output = curl_exec($ch); 824 | 825 | $this->_debug("Curl Result: '" . $output . "'"); 826 | 827 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 828 | $this->_debug("Curl Response Code: '" . $httpCode."'"); 829 | // Close the cURL resource, and free system resources 830 | 831 | $curlError = curl_errno($ch); 832 | curl_close($ch); 833 | if($curlError != CURLE_OK) 834 | { 835 | $this->_debug("CURL Request - There was a CURL error"); 836 | list(, $caller) = debug_backtrace(false); 837 | //var_dump($caller['function']); 838 | $errorText = $this->_curlErrorCode($curlError); 839 | $this->_setError($errorText, $caller['function']); 840 | return false; 841 | } 842 | else 843 | { 844 | $retVal = json_decode($output,true); 845 | 846 | if(json_last_error() == 0) 847 | { 848 | if(isset($retVal['error']) && $retVal['error']) 849 | { 850 | $this->_debug("CURL Request - API response contained 'error' field"); 851 | $errorText = $retVal['error']; 852 | $this->_setError($errorText, __FUNCTION__); 853 | return false; 854 | } 855 | else 856 | { 857 | $this->_debug("CURL Request - Returning True"); 858 | $this->_result = $retVal; 859 | return true; 860 | } 861 | } 862 | else 863 | { 864 | $this->_debug("CURL Request - Unable to parse JSON"); 865 | $errorText = "Unable to parse JSON. Json error = " . json_last_error() . ". See http://php.net/manual/en/function.json-last-error.php for more information. Raw response from Particle Cloud = '" . $result . "'"; 866 | $this->_setError($errorText, __FUNCTION__); 867 | return false; 868 | } 869 | } 870 | } 871 | 872 | /** 873 | * Private Function. Returns a human readable string for a given CURL Error Code 874 | * 875 | * @param int curlCode The CURL error code 876 | * 877 | * @return string A human-readable string version of the curlCode 878 | */ 879 | private function _curlErrorCode($curlCode) 880 | { 881 | switch ($curlCode) 882 | { 883 | case 26: 884 | return "Curl Error. There was a problem reading a local file or an error returned by the read callback."; 885 | case 30: 886 | return "Curl Error. Operation timeout. The specified time-out period was reached according to the conditions."; 887 | default: 888 | return "Curl Error. Error number = {$curlCode}. See http://curl.haxx.se/libcurl/c/libcurl-errors.html for more information"; 889 | } 890 | } 891 | 892 | } -------------------------------------------------------------------------------- /tests/ParticleAPITest.php: -------------------------------------------------------------------------------- 1 | setEndpoint("https://api.particle.io/"); 11 | 12 | $this->assertEquals(true,$result); 13 | $this->assertEquals("https://api.particle.io/",$particle->getEndpoint()); 14 | } 15 | 16 | public function test_setting_timeout() 17 | { 18 | $particle = new ParticleAPI; 19 | $result = $particle->setTimeout(15); 20 | 21 | $this->assertEquals(true,$result); 22 | $this->assertEquals(15,$particle->getTimeout()); 23 | } 24 | 25 | public function test_setting_non_numeric_value_for_timeout() 26 | { 27 | $particle = new ParticleAPI; 28 | $result = $particle->setTimeout('test'); 29 | 30 | $this->assertEquals(false,$result); 31 | $this->assertEquals('Non numeric timeout',$particle->getError()); 32 | $this->assertEquals('setTimeout',$particle->getErrorSource()); 33 | } 34 | 35 | public function test_setting_auth() 36 | { 37 | $particle = new ParticleAPI; 38 | $result = $particle->setAuth('test@test.com','password'); 39 | 40 | $this->assertEquals(true,$result); 41 | $this->assertEquals('test@test.com',$particle->getEmail()); 42 | $this->assertEquals('password',$particle->getPassword()); 43 | } 44 | 45 | public function test_clearing_auth() 46 | { 47 | $particle = new ParticleAPI; 48 | $result = $particle->clearAuth(); 49 | 50 | $this->assertEquals(true,$result); 51 | $this->assertEquals(false, $particle->getEmail()); 52 | $this->assertEquals(false,$particle->getPassword()); 53 | } 54 | 55 | public function test_setting_access_token() 56 | { 57 | $particle = new ParticleAPI; 58 | $result = $particle->setAccessToken('a5a7b2d620fa349c8e825f02a6513de6ca7baabb'); 59 | 60 | $this->assertEquals(true,$result); 61 | $this->assertEquals('a5a7b2d620fa349c8e825f02a6513de6ca7baabb',$particle->getAccessToken()); 62 | } 63 | 64 | public function test_clearing_access_token() 65 | { 66 | $particle = new ParticleAPI; 67 | $result = $particle->clearAccessToken(); 68 | 69 | $this->assertEquals(true,$result); 70 | $this->assertEquals(false,$particle->getAccessToken()); 71 | } 72 | 73 | public function test_setting_debug_type() 74 | { 75 | $particle = new ParticleAPI; 76 | $result = $particle->setDebugType('TEXT'); 77 | 78 | $this->assertEquals(true,$result); 79 | $this->assertEquals('TEXT',$particle->getDebugType()); 80 | } 81 | 82 | public function test_setting_debug_type_invalid() 83 | { 84 | $particle = new ParticleAPI; 85 | $result = $particle->setDebugType('SomethingStrange'); 86 | 87 | $this->assertEquals(false,$result); 88 | $this->assertContains('Bad debut type',$particle->getError()); 89 | $this->assertEquals('HTML',$particle->getDebugType()); 90 | } 91 | 92 | public function test_setting_debug_to_true() 93 | { 94 | $particle = new ParticleAPI; 95 | $result = $particle->setDebug(true); 96 | 97 | $this->assertEquals(true,$result); 98 | $this->assertEquals(true,$particle->getDebug()); 99 | } 100 | 101 | public function test_setting_disable_ssl_to_true() 102 | { 103 | $particle = new ParticleAPI; 104 | $result = $particle->setDisableSSL(true); 105 | 106 | $this->assertEquals(true,$result); 107 | $this->assertEquals(true,$particle->getDisableSSL()); 108 | } 109 | 110 | public function test_setting_debug_message() 111 | { 112 | $particle = new ParticleAPI; 113 | $result = $particle->debug('debugging text'); 114 | 115 | $this->assertEquals(true,$result); 116 | } 117 | 118 | 119 | } --------------------------------------------------------------------------------