diff --git a/LICENSE b/LICENSE.md similarity index 99% rename from LICENSE rename to LICENSE.md index 65c5ca8..6600f1c 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,4 +1,4 @@ - GNU LESSER GENERAL PUBLIC LICENSE +GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. diff --git a/README.md b/README.md new file mode 100644 index 0000000..209a1a5 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +Pure PHP PJLink Class1 library +============================== + +The PJLink PHP class is the lightest pure PHP package available for +operating and controlling data projectors using the PJLink Class1 standard. + +PJLink Class1 specifications are available here: + http://pjlink.jbmia.or.jp/english/data/5-1_PJLink_eng_20131210.pdf + +(c) 2017 SysCo systemes de communication sa +http://developer.sysco.ch/php/ + +Current build: 1.0.0.1 (2017.04.24) + +No external file is needed (no PEAR, no PECL, no cURL). + + +# Licence + + Copyright (c) 2017 SysCo systemes de communication sa + SysCo (tm) is a trademark of SysCo systemes de communication sa + (http://www.sysco.ch/) + All rights reserved. + + PJLink PHP class is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + PJLink PHP class is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PJLink PHP class. + If not, see . + + +# Usage + + Every command send to the projector return false is something is wrong. + The error message can be detailed by calling the getError() method. + + Public methods available: + setDevice($host, [[[$password], $timeout], $port]) + powerOn([[[[$host], $password], $timeout], $port]) + powerOff([[[[$host], $password], $timeout], $port]) + getPowerState([[[[$host], $password], $timeout], $port]) + setInput($input, [[[[$host], $password], $timeout], $port]) + getInput([[[[$host], $password], $timeout], $port]) + getErrorState([[[[$host], $password], $timeout], $port]) + getLampState([[[[$host], $password], $timeout], $port]) + getName([[[[$host], $password], $timeout], $port]) + getManufactureName([[[[$host], $password], $timeout], $port]) + getProductName([[[[$host], $password], $timeout], $port]) + getOtherInfo([[[[$host], $password], $timeout], $port]) + getClass([[[[$host], $password], $timeout], $port]) + getError() + getErrorNumber() + getResponseRaw() + getResponseText() + + +# Examples + + // Example 1 + require_once('pjlink.class.php'); + $pjlink = new PJLink(); + if (false === $pjlink->powerOn("192.168.0.1")) { + echo $pjlink->getError(); + } elseif (false === $pjlink->setInput(11, "192.168.0.1")) { + echo $pjlink->getError(); + } + + // Example 2 + require_once('pjlink.class.php'); + $pjlink = new PJLink(); + $pjlink->setDevice("192.168.0.1", "my_pjlink_pass", 10, 4352); + if (false === $pjlink->powerOn()) { + echo $pjlink->getError(); + } elseif (false === $pjlink->setInput(11)) { + echo $pjlink->getError(); + } + echo "Device: ".$pjlink->getManufactureName().", ".$pjlink->getProductName()."
\n"; + + +You can support our open source projects with donations and sponsoring. +Sponsorships are crucial for ongoing and future development! +If you'd like to support our work, then consider making a donation, any support +is always welcome even if it's as low as $1! +You can also sponsor the development of a specific feature. Please contact +us in order to discuss the detail of the implementation. + +**[Donate via PayPal by clicking here][1].** [![Donate via PayPal][2]][1] +[1]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N56M9E2SEAUD4 +[2]: https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg + + +And for more PHP classes, have a look on [PHPclasses.org](http://syscoal.users.phpclasses.org/browse/), where a lot of authors are sharing their classes for free. \ No newline at end of file diff --git a/example1.php b/example1.php new file mode 100644 index 0000000..15b8a1f --- /dev/null +++ b/example1.php @@ -0,0 +1,11 @@ +powerOn("192.168.0.1")) { + echo $pjlink->getError(); + } elseif (false === $pjlink->setInput(11, "192.168.0.1")) { + echo $pjlink->getError(); + } +?> \ No newline at end of file diff --git a/example2.php b/example2.php new file mode 100644 index 0000000..a8bce4c --- /dev/null +++ b/example2.php @@ -0,0 +1,15 @@ +setDevice("192.168.0.1", "my_pjlink_pass", 10, 4352); + + if (false === $pjlink->powerOn()) { + echo $pjlink->getError(); + } elseif (false === $pjlink->setInput(11)) { + echo $pjlink->getError(); + } + + echo "Device: ".$pjlink->getManufactureName().", ".$pjlink->getProductName()."
\n"; +?> \ No newline at end of file diff --git a/pjlink.class.php b/pjlink.class.php new file mode 100644 index 0000000..caa89dc --- /dev/null +++ b/pjlink.class.php @@ -0,0 +1,740 @@ + + * @version 1.0.0.1 + * @date 2017-04-24 + * @since 2017-04-23 + * @copyright (c) 2017 SysCo systemes de communication sa + * @copyright GNU Lesser General Public License + * + *//* + * + * LICENCE + * + * Copyright (c) 2017 SysCo systemes de communication sa + * SysCo (tm) is a trademark of SysCo systemes de communication sa + * (http://www.sysco.ch/) + * All rights reserved. + * + * PJLink PHP class is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * PJLink PHP class is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with PJLink PHP class. + * If not, see . + * + * + * Usage + * + * Every command send to the projector return false is something is wrong. + * The error message can be detailed by calling the getError() method. + * + * Public methods available: + * setDevice($host, [[[$password], $timeout], $port]) + * powerOn([[[[$host], $password], $timeout], $port]) + * powerOff([[[[$host], $password], $timeout], $port]) + * getPowerState([[[[$host], $password], $timeout], $port]) + * setInput($input, [[[[$host], $password], $timeout], $port]) + * getInput([[[[$host], $password], $timeout], $port]) + * getErrorState([[[[$host], $password], $timeout], $port]) + * getLampState([[[[$host], $password], $timeout], $port]) + * getName([[[[$host], $password], $timeout], $port]) + * getManufactureName([[[[$host], $password], $timeout], $port]) + * getProductName([[[[$host], $password], $timeout], $port]) + * getOtherInfo([[[[$host], $password], $timeout], $port]) + * getClass([[[[$host], $password], $timeout], $port]) + * getError() + * getErrorNumber() + * getResponseRaw() + * getResponseText() + * + * + * Examples + * + * // Example 1 + * require_once('pjlink.class.php'); + * $pjlink = new PJLink(); + * if (false === $pjlink->powerOn("192.168.0.1")) { + * echo $pjlink->getError(); + * } elseif (false === $pjlink->setInput(11, "192.168.0.1")) { + * echo $pjlink->getError(); + * } + * + * + * // Example 2 + * require_once('pjlink.class.php'); + * $pjlink = new PJLink(); + * $pjlink->setDevice("192.168.0.1", "my_pjlink_pass", 10, 4352); + * if (false === $pjlink->powerOn()) { + * echo $pjlink->getError(); + * } elseif (false === $pjlink->setInput(11)) { + * echo $pjlink->getError(); + * } + * echo "Device: ".$pjlink->getManufactureName().", ".$pjlink->getProductName()."
\n"; + * + * + * No external file is needed (no PEAR, no PECL, no cURL). + * + * + * Special issues + * + * If you need specific developements concerning strong authentication, + * do not hesistate to contact us per email at developer@sysco.ch. + * + * + * Users feedbacks and comments + * + * 2017-04-24 SysCo/al (CH) + * First public version + * + * + * Change Log + * + * 2017-04-24 1.0.0.1 SysCo/al First public version + * 2017-04-23 1.0.0.0 SysCo/al Initial implementation + *********************************************************************/ + +// PJLINK constants +define ("PJLINK_OK", 0); +define ("PJLINK_BAD_DEVICE", 20); +define ("PJLINK_NO_CONNECTION", 21); +define ("PJLINK_AUTH_ERROR", 22); +define ("PJLINK_SEND_ERROR", 23); + +define ("PJLINK_CLASS", "1"); +define ("PJLINK_DEFAULT_PORT", 4352); +define ("PJLINK_DEFAULT_TIMEOUT", 5); +define ("PJLINK_PREFIX", "%"); + +class PJLink +{ + var $host = ""; + var $password = ""; + var $timeout = PJLINK_DEFAULT_TIMEOUT; + var $port = PJLINK_DEFAULT_PORT; + var $socket = NULL; + var $error = ""; + var $error_number = ""; + var $prefix_hash = ""; + var $response_raw = ""; + var $response_text = ""; + + public function getError() + { + return $this->error; + } + + public function getErrorNumber() + { + return $this->error_number; + } + + public function getResponseRaw() + { + return $this->response_raw; + } + + public function getResponseText() + { + return $this->response_text; + } + + public function setDevice( + $host, + $password = "", + $timeout = PJLINK_DEFAULT_TIMEOUT, + $port = PJLINK_DEFAULT_PORT + ) { + + $this->error = ""; + $this->error_number = PJLINK_OK; + + $this->host = $host; + $this->password = $password; + $this->timeout = $timeout; + $this->port = $port; + + if ($host == '') { + $this->error = "Host not defined"; + $this->error_number = PJLINK_BAD_DEVICE; + return false; + } + + return true; + } + + private function open( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + + $this->error = ""; + $this->error_number = PJLINK_OK; + + if ($host !== "") { + $this->host = $host; + } + + if ($password !== "") { + $this->password = $password; + } + + if ($timeout !== 0) { + $this->timeout = intval($timeout); + } + + if (intval($port) > 0) { + $this->port = intval($port); + } + + if ($this->host == '') { + $this->error = "Host not defined"; + $this->error_number = PJLINK_BAD_DEVICE; + return false; + } + + $errno = 0; + $errstr = ""; + + $this->socket = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); + + if (!$this->socket) { + $this->error = "Connection failed: " . socket_strerror($errno); + $this->error_number = PJLINK_NO_CONNECTION; + return false; + } + + stream_set_timeout($this->socket, $this->timeout, 0); + + $response = $this->getResponse(); + + if (FALSE !== strpos($response, "PJLINK 0")) { + $this->prefix_hash = ""; + return true; + } elseif (FALSE !== strpos($response, "PJLINK 1")) { + $auth_random = trim(substr($response, strpos($response, "PJLINK 1") + 9)); + $this->prefix_hash = md5($auth_random . $password); + return true; + } else { + $this->error = "Bad answer, connection failed"; + $this->error_number = PJLINK_NO_CONNECTION; + return false; + } + } + + + private function sendCommand( + $command + ) { + + $this->error = ""; + $this->error_number = PJLINK_OK; + $this->response_raw = ""; + $this->response_text = ""; + + if (!$this->socket) { + $this->error = "Device not connected"; + $this->error_number = PJLINK_NO_CONNECTION; + return false; + } + + if (FALSE === fwrite($this->socket, $this->prefix_hash . $command . chr(13))) { + $this->error = "Error sending command ".$command; + $this->error_number = PJLINK_SEND_ERROR; + return false; + } + + $response = $this->getResponse(); + + if (FALSE !== strpos($response, "PJLINK ERRA")) { + $this->error = "Authentication failed"; + $this->error_number = PJLINK_AUTH_ERROR; + return false; + } elseif (FALSE !== strpos($response, PJLINK_PREFIX)) { + $result = trim(substr($response, strpos($response, "=") + 1)); + if (0 === strpos($result, "ERR")) { + $this->response_text = $result; + return false; + } else { + return $result; + } + } else { + $this->error = "Error sending command ".$command; + $this->error_number = PJLINK_SEND_ERROR; + return false; + } + } + + + private function getResponse() + { + + $this->error = ""; + $this->error_number = PJLINK_OK; + $this->response_raw = ""; + $this->response_text = ""; + + $response = ''; + if (!$this->socket) { + $this->error = "Device not connected"; + $this->error_number = PJLINK_NO_CONNECTION; + return false; + } + + while (true) { + $char = fgetc($this->socket); + if (($char !== false) && ($char !== chr(13))) { + $response.= $char; + } else { + $this->response_raw = $response; + $this->response_text = $response; + return $response; + } + } + } + + + private function close() + { + + $this->error = ""; + $this->error_number = PJLINK_OK; + + if (!$this->socket) { + $this->error = "Device not connected"; + $this->error_number = PJLINK_NO_CONNECTION; + return false; + } else { + fclose($this->socket); + return true; + } + } + + public function powerOn( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "POWR 1"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + switch ($result) { + default: + $this->response_text = $result; + } + } else { + switch ($this->response_text) { + case 'ERR2': + $this->response_text = "out-of-parameter"; + break; + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function powerOff( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "POWR 0"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + switch ($result) { + default: + $this->response_text = $result; + } + } else { + switch ($this->response_text) { + case 'ERR2': + $this->response_text = "out-of-parameter"; + break; + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getPowerState( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "POWR ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + switch ($result) { + case '0': + $this->response_text = "off"; + break; + case '1': + $this->response_text = "on"; + break; + case '2': + $this->response_text = "cooling"; + break; + case '3': + $this->response_text = "warm-up"; + break; + default: + $this->response_text = $result; + } + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function setInput( + $input, + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "INPT " . $input; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + switch ($result) { + default: + $this->response_text = $result; + } + } else { + switch ($this->response_text) { + case 'ERR2': + $this->response_text = "nonexistent"; + break; + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getInput( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "INPT ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + switch ($result) { + default: + $this->response_text = $result; + } + } else { + switch ($this->response_text) { + case 'ERR2': + $this->response_text = "nonexistent"; + break; + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getErrorState( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "ERST ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = ""; + if (substr($result, 0, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "FAN: " . ((substr($result, 0, 1) == "1") ? "WARNING" : "ERROR"); + } + if (substr($result, 1, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "LAMP: " . ((substr($result, 1, 1) == "1") ? "WARNING" : "ERROR"); + } + if (substr($result, 2, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "TEMPERATURE: " . ((substr($result, 2, 1) == "1") ? "WARNING" : "ERROR"); + } + if (substr($result, 3, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "COVER OPEN: " . ((substr($result, 3, 1) == "1") ? "WARNING" : "ERROR"); + } + if (substr($result, 4, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "FILTER: " . ((substr($result, 4, 1) == "1") ? "WARNING" : "ERROR"); + } + if (substr($result, 5, 1) != "0") { + $this->response_text.= ($this->response_text != "" ? ", " : "") . "OTHER: " . ((substr($result, 5, 1) == "1") ? "WARNING" : "ERROR"); + } + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getLampState( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "LAMP ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $lamps = explode(" ", $result); + // TODO more details + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR1': + $this->response_text = "no-lamp"; + break; + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getName( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "NAME ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getManufactureName( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "INF1 ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getProductName( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "INF2 ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getOtherInfo( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "INFO ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + + public function getClass( + $host = "", + $password = "", + $timeout = 0, + $port = 0 + ) { + $command = PJLINK_PREFIX . PJLINK_CLASS . "CLSS ?"; + if ($this->open($host, $password, $timeout, $port)) { + $result = $this->sendCommand($command); + if (false !== $result) { + $this->response_text = $result; + } else { + switch ($this->response_text) { + case 'ERR3': + $this->response_text = "unavailable"; + break; + case 'ERR4': + $this->response_text = "failure"; + break; + } + $this->error = $this->response_text; + } + return $result; + } else { + return false; + } + } + +} \ No newline at end of file