├── PhpEpsolarTracer.php ├── PhpSerial.php ├── PhpSerialModbus.php ├── README.md ├── example_cli.dat ├── example_cli.php ├── example_json.php └── example_web.php /PhpEpsolarTracer.php: -------------------------------------------------------------------------------- 1 | tracer = new PhpSerialModbus; 194 | if (php_sapi_name() == "cli") file_exists($port) or die("Cannot open serial port $port\n"); 195 | $this->tracer->deviceInit($port,115200,'none',8,1,'none'); 196 | $this->tracer->deviceOpen(); 197 | // $this->tracer->debug=true; 198 | } 199 | 200 | public function __destruct() { 201 | $this->tracer->deviceClose(); 202 | } 203 | 204 | // Convert data received from Modbus 205 | // where $doublebytes is an array with indexes of value that needs four bytes 206 | // instead of just two and $negbytes contains indexes of value that could be negative 207 | private function convertData($respArray,$doubleBytes=Array(),$negBytes=Array()) { 208 | $resultArray=[]; 209 | // Iterate response array and aggregate Lo and Hi byte 210 | for ($i = 0; $i<(count($respArray)/2); $i++) { 211 | $data=$respArray[$i*2].$respArray[$i*2+1]; 212 | if (in_array($i,$negBytes)) $negByte=true; else $negByte=false; 213 | // echo "0x".$data."\n"; 214 | if ($negByte && ("0x".$data>0x7FFF)) { 215 | $data=dechex(0xFFFF-("0x".$data)); 216 | $neg=true; 217 | } else $neg=false; 218 | // echo "0x".$data."\n"; 219 | // If we need two bytes more, add them and increase counter 220 | if (in_array($i,$doubleBytes)) { 221 | $dataH=$respArray[$i*2+2].$respArray[$i*2+3]; 222 | if ($negByte && ("0x".$dataH>0x7FFF)) $dataH=dechex(0xFFFF-("0x".$dataH)); 223 | // echo $dataH."-".$data."\n"; 224 | $data=$dataH.$data; 225 | $i++; 226 | } 227 | $resultArray[] = (!$neg) ? hexdec($data) : -hexdec($data); 228 | // echo $i.",".hexdec($data)."\n"; 229 | } 230 | return $resultArray; 231 | } 232 | 233 | // Convert two bytes response to single byte (for some responses) 234 | private function convert8bit ($inputDtArray) { 235 | $outputDtArray=[]; 236 | for ($i = 0; $i<(count($inputDtArray)); $i++) { 237 | $outputDtArray[$i*2] = (($inputDtArray[$i] >> 0) & 0xff); 238 | // echo ($inputDtArray[$i])."\n"; 239 | $outputDtArray[$i*2+1] = (($inputDtArray[$i] >> 8) & 0xff); 240 | } 241 | return $outputDtArray; 242 | } 243 | 244 | // Remove unused Indexes from array 245 | private function removeUnused (&$inputArray, $inputIndexes) { 246 | for ($i = 0; $i<(count($inputIndexes)); $i++) { 247 | array_splice($inputArray,$inputIndexes[$i]-$i,1); 248 | } 249 | } 250 | 251 | private function divide ($a, $b) { 252 | return $a/$b; 253 | } 254 | 255 | // Send query and get response for "Info data" 256 | public function getInfoData() { 257 | $this->tracer->sendRawQuery("\x01\x2b\x0e\x01\x00\x70\x77",false); 258 | $result=$this->tracer->getResponse(true); 259 | if ( (!$result) && (php_sapi_name() == "cli") ) die("Timeout on reading from serial port\n"); 260 | // $escaped = addcslashes($result, "\0..\37!@\177..\377"); 261 | // print $escaped."\n"; 262 | // print preg_replace( '/[^[:print:]]/', '.',$result); 263 | $string = preg_replace('/[\f\r]/u', ' - ', $result); 264 | $string = preg_replace('/[^A-Za-z0-9 _\-\+\&.,]/','',$string)."\n"; 265 | $this->infoData = explode(" - ",substr($string,1)); 266 | if (!$result) return 0; 267 | return 1; 268 | } 269 | 270 | // Send query and get response for "Rated data" 271 | public function getRatedData() { 272 | $this->tracer->sendRawQuery("\x01\x43\x30\x00\x00\x0f\x0b\x01",false); 273 | $result = $this->tracer->getResponse(false,2,10); 274 | if (!$result) return 0; 275 | $this->ratedData = $this->convertData($result,array(2,6)); 276 | $this->ratedData = array_map(array($this,'divide'),$this->ratedData,$this->ratedDiv); 277 | if (count($this->ratedData) != 8) return 0; 278 | return 1; 279 | } 280 | 281 | // Send query and get response for "Real-time data and status" 282 | public function getRealtimeData() { 283 | $this->tracer->sendRawQuery("\x01\x43\x31\x00\x00\x76\xcb\x1f",false); 284 | $result1 = $this->tracer->getResponse(false,15,190); 285 | if (!$result1) return 0; 286 | $this->tracer->sendRawQuery("\x01\x43\x32\x00\x00\x04\x4b\x7e",false); 287 | $result2=$this->tracer->getResponse(false,1,2); 288 | if (!$result2) return 0; 289 | $result=array_merge($result1,$result2); 290 | $this->realtimeData = $this->convertData($result,array(2,6,10,14),array(16,17,18,19,21)); 291 | $this->removeUnused($this->realtimeData,array(9,10,11,15,21)); 292 | $this->realtimeData = array_map(array($this,'divide'),$this->realtimeData,$this->realtimeDiv); 293 | if (count($this->realtimeData) != 17) return 0; 294 | return 1; 295 | } 296 | 297 | // Send query and get response for "Statistical parameter" 298 | public function getStatData() { 299 | $this->tracer->sendRawQuery("\x01\x43\x33\x00\x00\x76\xca\xa7",false); 300 | $result = $this->tracer->getResponse(false,15,174); 301 | if (!$result) return 0; 302 | $this->statData = $this->convertData($result,array(4,6,8,10,12,14,16,18,20,22,24,27),array(27,29,30)); 303 | $this->removeUnused($this->statData,array(13,14,15)); 304 | $this->statData = array_map(array($this,'divide'),$this->statData,$this->statDiv); 305 | if (count($this->statData) != 16) return 0; 306 | return 1; 307 | } 308 | 309 | // Send query and get response for "Settings parameter" 310 | public function getSettingData() { 311 | $this->tracer->sendRawQuery("\x01\x43\x90\x00\x00\x76\xe8\xe3",false); 312 | $result = $this->tracer->getResponse(false,15,124); 313 | if (!$result) return 0; 314 | $this->settingData = $this->convertData($result,array(),array(20)); 315 | // print_r($this->settingData); 316 | $dtArray=$this->convert8bit(array_slice($this->settingData,15,3)); 317 | array_splice($this->settingData, 15, 3, $dtArray); 318 | // print_r($this->settingData); 319 | $dtArray=$this->convert8bit(array_slice($this->settingData,34,2)); 320 | array_splice($this->settingData, 34, 2, $dtArray); 321 | // print_r($this->settingData); 322 | $dtArray=$this->convert8bit(array_slice($this->settingData,51,1)); 323 | array_splice($this->settingData, 51, 1, $dtArray); 324 | // print_r($this->settingData); 325 | $this->removeUnused($this->settingData,array(50,60)); 326 | $this->settingData = array_map(array($this,'divide'),$this->settingData,$this->settingDiv); 327 | if (count($this->settingData) != 60) return 0; 328 | return 1; 329 | } 330 | 331 | // Send query and get response for "Coils" 332 | public function getCoilData() { 333 | $this->tracer->sendRawQuery("\x01\x01\x00\x02\x00\x04\x9c\x09",false); 334 | $result = $this->tracer->getResponse(false); 335 | if (!$result) return 0; 336 | $this->coilData[0] = $result[0] & 1; 337 | $this->coilData[1] = ($result[0] >> 3) & 1; 338 | $this->coilData[2] = ($result[0] >> 4) & 1; 339 | return 1; 340 | } 341 | 342 | // Send query and get response for "Discrete input" 343 | public function getDiscreteData () { 344 | $this->tracer->sendRawQuery("\x01\x02\x20\x00\x00\x01\xb2\x0a",false); 345 | $result1 = $this->tracer->getResponse(false); 346 | if (!$result1) return 0; 347 | $this->tracer->sendRawQuery("\x01\x02\x20\x0c\x00\x01\x72\x09",false); 348 | $result2=$this->tracer->getResponse(false); 349 | if (!$result2) return 0; 350 | $result = array_merge($result1,$result2); 351 | $this->discreteData[0] = $result[0] & 1; 352 | $this->discreteData[1] = $result[1] & 1; 353 | if (count($this->discreteData) != 2) return 0; 354 | return 1; 355 | } 356 | } -------------------------------------------------------------------------------- /PhpSerial.php: -------------------------------------------------------------------------------- 1 | 13 | * @author Rizwan Kassim 14 | * @thanks Aurélien Derouineau for finding how to open serial ports with windows 15 | * @thanks Alec Avedisyan for help and testing with reading 16 | * @thanks Jim Wright for OSX cleanup/fixes. 17 | * @copyright under GPL 2 licence 18 | */ 19 | class PhpSerial 20 | { 21 | public $_device = null; 22 | public $_winDevice = null; 23 | public $_dHandle = null; 24 | public $_dState = SERIAL_DEVICE_NOTSET; 25 | public $_buffer = ""; 26 | public $_os = ""; 27 | 28 | /** 29 | * This var says if buffer should be flushed by sendMessage (true) or 30 | * manually (false) 31 | * 32 | * @var bool 33 | */ 34 | public $autoFlush = true; 35 | 36 | /** 37 | * Constructor. Perform some checks about the OS and setserial 38 | * 39 | * @return PhpSerial 40 | */ 41 | public function PhpSerial() 42 | { 43 | setlocale(LC_ALL, "en_US"); 44 | 45 | $sysName = php_uname(); 46 | 47 | if (substr($sysName, 0, 5) === "Linux") { 48 | $this->_os = "linux"; 49 | 50 | if ($this->_exec("stty --version") === 0) { 51 | register_shutdown_function(array($this, "deviceClose")); 52 | } else { 53 | trigger_error( 54 | "No stty availible, unable to run.", 55 | E_USER_ERROR 56 | ); 57 | } 58 | } elseif (substr($sysName, 0, 6) === "Darwin") { 59 | $this->_os = "osx"; 60 | register_shutdown_function(array($this, "deviceClose")); 61 | } elseif (substr($sysName, 0, 7) === "Windows") { 62 | $this->_os = "windows"; 63 | register_shutdown_function(array($this, "deviceClose")); 64 | } else { 65 | trigger_error("Host OS is neither osx, linux nor windows, unable " . 66 | "to run.", E_USER_ERROR); 67 | exit(); 68 | } 69 | } 70 | 71 | // 72 | // OPEN/CLOSE DEVICE SECTION -- {START} 73 | // 74 | 75 | /** 76 | * Device set function : used to set the device name/address. 77 | * -> linux : use the device address, like /dev/ttyS0 78 | * -> osx : use the device address, like /dev/tty.serial 79 | * -> windows : use the COMxx device name, like COM1 (can also be used 80 | * with linux) 81 | * 82 | * @param string $device the name of the device to be used 83 | * @return bool 84 | */ 85 | public function deviceSet($device) 86 | { 87 | if ($this->_dState !== SERIAL_DEVICE_OPENED) { 88 | if ($this->_os === "linux") { 89 | if (preg_match("@^COM(\\d+):?$@i", $device, $matches)) { 90 | $device = "/dev/ttyS" . ($matches[1] - 1); 91 | } 92 | 93 | if ($this->_exec("stty -F " . $device) === 0) { 94 | $this->_device = $device; 95 | $this->_dState = SERIAL_DEVICE_SET; 96 | 97 | return true; 98 | } 99 | } elseif ($this->_os === "osx") { 100 | if ($this->_exec("stty -f " . $device) === 0) { 101 | $this->_device = $device; 102 | $this->_dState = SERIAL_DEVICE_SET; 103 | 104 | return true; 105 | } 106 | } elseif ($this->_os === "windows") { 107 | if (preg_match("@^COM(\\d+):?$@i", $device, $matches) 108 | and $this->_exec( 109 | exec("mode " . $device . " xon=on BAUD=9600") 110 | ) === 0 111 | ) { 112 | $this->_winDevice = "COM" . $matches[1]; 113 | $this->_device = "\\.com" . $matches[1]; 114 | $this->_dState = SERIAL_DEVICE_SET; 115 | 116 | return true; 117 | } 118 | } 119 | 120 | trigger_error("Specified serial port is not valid", E_USER_WARNING); 121 | 122 | return false; 123 | } else { 124 | trigger_error("You must close your device before to set an other " . 125 | "one", E_USER_WARNING); 126 | 127 | return false; 128 | } 129 | } 130 | 131 | /** 132 | * Opens the device for reading and/or writing. 133 | * 134 | * @param string $mode Opening mode : same parameter as fopen() 135 | * @return bool 136 | */ 137 | public function deviceOpen($mode = "r+b") 138 | { 139 | if ($this->_dState === SERIAL_DEVICE_OPENED) { 140 | trigger_error("The device is already opened", E_USER_NOTICE); 141 | 142 | return true; 143 | } 144 | 145 | if ($this->_dState === SERIAL_DEVICE_NOTSET) { 146 | trigger_error( 147 | "The device must be set before to be open", 148 | E_USER_WARNING 149 | ); 150 | 151 | return false; 152 | } 153 | 154 | if (!preg_match("@^[raw]\\+?b?$@", $mode)) { 155 | trigger_error( 156 | "Invalid opening mode : ".$mode.". Use fopen() modes.", 157 | E_USER_WARNING 158 | ); 159 | 160 | return false; 161 | } 162 | 163 | $this->_dHandle = @fopen($this->_device, $mode); 164 | 165 | if ($this->_dHandle !== false) { 166 | stream_set_blocking($this->_dHandle, 0); 167 | $this->_dState = SERIAL_DEVICE_OPENED; 168 | 169 | return true; 170 | } 171 | 172 | $this->_dHandle = null; 173 | trigger_error("Unable to open the device", E_USER_WARNING); 174 | 175 | return false; 176 | } 177 | 178 | /** 179 | * Closes the device 180 | * 181 | * @return bool 182 | */ 183 | public function deviceClose() 184 | { 185 | if ($this->_dState !== SERIAL_DEVICE_OPENED) { 186 | return true; 187 | } 188 | 189 | if (fclose($this->_dHandle)) { 190 | $this->_dHandle = null; 191 | $this->_dState = SERIAL_DEVICE_SET; 192 | 193 | return true; 194 | } 195 | 196 | trigger_error("Unable to close the device", E_USER_ERROR); 197 | 198 | return false; 199 | } 200 | 201 | // 202 | // OPEN/CLOSE DEVICE SECTION -- {STOP} 203 | // 204 | 205 | // 206 | // CONFIGURE SECTION -- {START} 207 | // 208 | 209 | /** 210 | * Configure the Baud Rate 211 | * Possible rates : 110, 150, 300, 600, 1200, 2400, 4800, 9600, 38400, 212 | * 57600 and 115200. 213 | * 214 | * @param int $rate the rate to set the port in 215 | * @return bool 216 | */ 217 | public function confBaudRate($rate) 218 | { 219 | if ($this->_dState !== SERIAL_DEVICE_SET) { 220 | trigger_error("Unable to set the baud rate : the device is " . 221 | "either not set or opened", E_USER_WARNING); 222 | 223 | return false; 224 | } 225 | 226 | $validBauds = array ( 227 | 110 => 11, 228 | 150 => 15, 229 | 300 => 30, 230 | 600 => 60, 231 | 1200 => 12, 232 | 2400 => 24, 233 | 4800 => 48, 234 | 9600 => 96, 235 | 19200 => 19, 236 | 38400 => 38400, 237 | 57600 => 57600, 238 | 115200 => 115200 239 | ); 240 | 241 | if (isset($validBauds[$rate])) { 242 | if ($this->_os === "linux") { 243 | $ret = $this->_exec( 244 | "stty -F " . $this->_device . " " . (int) $rate, 245 | $out 246 | ); 247 | } elseif ($this->_os === "osx") { 248 | $ret = $this->_exec( 249 | "stty -f " . $this->_device . " " . (int) $rate, 250 | $out 251 | ); 252 | } elseif ($this->_os === "windows") { 253 | $ret = $this->_exec( 254 | "mode " . $this->_winDevice . " BAUD=" . $validBauds[$rate], 255 | $out 256 | ); 257 | } else { 258 | return false; 259 | } 260 | 261 | if ($ret !== 0) { 262 | trigger_error( 263 | "Unable to set baud rate: " . $out[1], 264 | E_USER_WARNING 265 | ); 266 | 267 | return false; 268 | } 269 | 270 | return true; 271 | } else { 272 | return false; 273 | } 274 | } 275 | 276 | /** 277 | * Configure parity. 278 | * Modes : odd, even, none 279 | * 280 | * @param string $parity one of the modes 281 | * @return bool 282 | */ 283 | public function confParity($parity) 284 | { 285 | if ($this->_dState !== SERIAL_DEVICE_SET) { 286 | trigger_error( 287 | "Unable to set parity : the device is either not set or opened", 288 | E_USER_WARNING 289 | ); 290 | 291 | return false; 292 | } 293 | 294 | $args = array( 295 | "none" => "-parenb", 296 | "odd" => "parenb parodd", 297 | "even" => "parenb -parodd", 298 | ); 299 | 300 | if (!isset($args[$parity])) { 301 | trigger_error("Parity mode not supported", E_USER_WARNING); 302 | 303 | return false; 304 | } 305 | 306 | if ($this->_os === "linux") { 307 | $ret = $this->_exec( 308 | "stty -F " . $this->_device . " " . $args[$parity], 309 | $out 310 | ); 311 | } elseif ($this->_os === "osx") { 312 | $ret = $this->_exec( 313 | "stty -f " . $this->_device . " " . $args[$parity], 314 | $out 315 | ); 316 | } else { 317 | $ret = $this->_exec( 318 | "mode " . $this->_winDevice . " PARITY=" . $parity{0}, 319 | $out 320 | ); 321 | } 322 | 323 | if ($ret === 0) { 324 | return true; 325 | } 326 | 327 | trigger_error("Unable to set parity : " . $out[1], E_USER_WARNING); 328 | 329 | return false; 330 | } 331 | 332 | /** 333 | * Sets the length of a character. 334 | * 335 | * @param int $int length of a character (5 <= length <= 8) 336 | * @return bool 337 | */ 338 | public function confCharacterLength($int) 339 | { 340 | if ($this->_dState !== SERIAL_DEVICE_SET) { 341 | trigger_error("Unable to set length of a character : the device " . 342 | "is either not set or opened", E_USER_WARNING); 343 | 344 | return false; 345 | } 346 | 347 | $int = (int) $int; 348 | if ($int < 5) { 349 | $int = 5; 350 | } elseif ($int > 8) { 351 | $int = 8; 352 | } 353 | 354 | if ($this->_os === "linux") { 355 | $ret = $this->_exec( 356 | "stty -F " . $this->_device . " cs" . $int, 357 | $out 358 | ); 359 | } elseif ($this->_os === "osx") { 360 | $ret = $this->_exec( 361 | "stty -f " . $this->_device . " cs" . $int, 362 | $out 363 | ); 364 | } else { 365 | $ret = $this->_exec( 366 | "mode " . $this->_winDevice . " DATA=" . $int, 367 | $out 368 | ); 369 | } 370 | 371 | if ($ret === 0) { 372 | return true; 373 | } 374 | 375 | trigger_error( 376 | "Unable to set character length : " .$out[1], 377 | E_USER_WARNING 378 | ); 379 | 380 | return false; 381 | } 382 | 383 | /** 384 | * Sets the length of stop bits. 385 | * 386 | * @param float $length the length of a stop bit. It must be either 1, 387 | * 1.5 or 2. 1.5 is not supported under linux and on 388 | * some computers. 389 | * @return bool 390 | */ 391 | public function confStopBits($length) 392 | { 393 | if ($this->_dState !== SERIAL_DEVICE_SET) { 394 | trigger_error("Unable to set the length of a stop bit : the " . 395 | "device is either not set or opened", E_USER_WARNING); 396 | 397 | return false; 398 | } 399 | 400 | if ($length != 1 401 | and $length != 2 402 | and $length != 1.5 403 | and !($length == 1.5 and $this->_os === "linux") 404 | ) { 405 | trigger_error( 406 | "Specified stop bit length is invalid", 407 | E_USER_WARNING 408 | ); 409 | 410 | return false; 411 | } 412 | 413 | if ($this->_os === "linux") { 414 | $ret = $this->_exec( 415 | "stty -F " . $this->_device . " " . 416 | (($length == 1) ? "-" : "") . "cstopb", 417 | $out 418 | ); 419 | } elseif ($this->_os === "osx") { 420 | $ret = $this->_exec( 421 | "stty -f " . $this->_device . " " . 422 | (($length == 1) ? "-" : "") . "cstopb", 423 | $out 424 | ); 425 | } else { 426 | $ret = $this->_exec( 427 | "mode " . $this->_winDevice . " STOP=" . $length, 428 | $out 429 | ); 430 | } 431 | 432 | if ($ret === 0) { 433 | return true; 434 | } 435 | 436 | trigger_error( 437 | "Unable to set stop bit length : " . $out[1], 438 | E_USER_WARNING 439 | ); 440 | 441 | return false; 442 | } 443 | 444 | /** 445 | * Configures the flow control 446 | * 447 | * @param string $mode Set the flow control mode. Availible modes : 448 | * -> "none" : no flow control 449 | * -> "rts/cts" : use RTS/CTS handshaking 450 | * -> "xon/xoff" : use XON/XOFF protocol 451 | * @return bool 452 | */ 453 | public function confFlowControl($mode) 454 | { 455 | if ($this->_dState !== SERIAL_DEVICE_SET) { 456 | trigger_error("Unable to set flow control mode : the device is " . 457 | "either not set or opened", E_USER_WARNING); 458 | 459 | return false; 460 | } 461 | 462 | $linuxModes = array( 463 | "none" => "clocal -crtscts -ixon -ixoff", 464 | "rts/cts" => "-clocal crtscts -ixon -ixoff", 465 | "xon/xoff" => "-clocal -crtscts ixon ixoff" 466 | ); 467 | $windowsModes = array( 468 | "none" => "xon=off octs=off rts=on", 469 | "rts/cts" => "xon=off octs=on rts=hs", 470 | "xon/xoff" => "xon=on octs=off rts=on", 471 | ); 472 | 473 | if ($mode !== "none" and $mode !== "rts/cts" and $mode !== "xon/xoff") { 474 | trigger_error("Invalid flow control mode specified", E_USER_ERROR); 475 | 476 | return false; 477 | } 478 | 479 | if ($this->_os === "linux") { 480 | $ret = $this->_exec( 481 | "stty -F " . $this->_device . " " . $linuxModes[$mode], 482 | $out 483 | ); 484 | } elseif ($this->_os === "osx") { 485 | $ret = $this->_exec( 486 | "stty -f " . $this->_device . " " . $linuxModes[$mode], 487 | $out 488 | ); 489 | } else { 490 | $ret = $this->_exec( 491 | "mode " . $this->_winDevice . " " . $windowsModes[$mode], 492 | $out 493 | ); 494 | } 495 | 496 | if ($ret === 0) { 497 | return true; 498 | } else { 499 | trigger_error( 500 | "Unable to set flow control : " . $out[1], 501 | E_USER_ERROR 502 | ); 503 | 504 | return false; 505 | } 506 | } 507 | 508 | /** 509 | * Sets a setserial parameter (cf man setserial) 510 | * NO MORE USEFUL ! 511 | * -> No longer supported 512 | * -> Only use it if you need it 513 | * 514 | * @param string $param parameter name 515 | * @param string $arg parameter value 516 | * @return bool 517 | */ 518 | public function setSetserialFlag($param, $arg = "") 519 | { 520 | if (!$this->_ckOpened()) { 521 | return false; 522 | } 523 | 524 | $return = exec( 525 | "setserial " . $this->_device . " " . $param . " " . $arg . " 2>&1" 526 | ); 527 | 528 | if ($return{0} === "I") { 529 | trigger_error("setserial: Invalid flag", E_USER_WARNING); 530 | 531 | return false; 532 | } elseif ($return{0} === "/") { 533 | trigger_error("setserial: Error with device file", E_USER_WARNING); 534 | 535 | return false; 536 | } else { 537 | return true; 538 | } 539 | } 540 | 541 | // 542 | // CONFIGURE SECTION -- {STOP} 543 | // 544 | 545 | // 546 | // I/O SECTION -- {START} 547 | // 548 | 549 | /** 550 | * Sends a string to the device 551 | * 552 | * @param string $str string to be sent to the device 553 | * @param float $waitForReply time to wait for the reply (in seconds) 554 | */ 555 | public function sendMessage($str, $waitForReply = 0.1) 556 | { 557 | $this->_buffer .= $str; 558 | 559 | if ($this->autoFlush === true) { 560 | $this->serialflush(); 561 | } 562 | 563 | usleep((int) ($waitForReply * 1000000)); 564 | } 565 | 566 | /** 567 | * Reads the port until no new datas are availible, then return the content. 568 | * 569 | * @param int $count Number of characters to be read (will stop before 570 | * if less characters are in the buffer) 571 | * @return string 572 | */ 573 | public function readPort($count = 0) 574 | { 575 | if ($this->_dState !== SERIAL_DEVICE_OPENED) { 576 | trigger_error("Device must be opened to read it", E_USER_WARNING); 577 | 578 | return false; 579 | } 580 | 581 | if ($this->_os === "linux" || $this->_os === "osx") { 582 | // Behavior in OSX isn't to wait for new data to recover, but just 583 | // grabs what's there! 584 | // Doesn't always work perfectly for me in OSX 585 | $content = ""; $i = 0; 586 | 587 | if ($count !== 0) { 588 | do { 589 | if ($i > $count) { 590 | $content .= fread($this->_dHandle, ($count - $i)); 591 | } else { 592 | $content .= fread($this->_dHandle, 128); 593 | } 594 | } while (($i += 128) === strlen($content)); 595 | } else { 596 | do { 597 | $content .= fread($this->_dHandle, 128); 598 | } while (($i += 128) === strlen($content)); 599 | } 600 | 601 | return $content; 602 | } elseif ($this->_os === "windows") { 603 | // Windows port reading procedures still buggy 604 | $content = ""; $i = 0; 605 | 606 | if ($count !== 0) { 607 | do { 608 | if ($i > $count) { 609 | $content .= fread($this->_dHandle, ($count - $i)); 610 | } else { 611 | $content .= fread($this->_dHandle, 128); 612 | } 613 | } while (($i += 128) === strlen($content)); 614 | } else { 615 | do { 616 | $content .= fread($this->_dHandle, 128); 617 | } while (($i += 128) === strlen($content)); 618 | } 619 | 620 | return $content; 621 | } 622 | 623 | return false; 624 | } 625 | 626 | /** 627 | * Flushes the output buffer 628 | * Renamed from flush for osx compat. issues 629 | * 630 | * @return bool 631 | */ 632 | public function serialflush() 633 | { 634 | if (!$this->_ckOpened()) { 635 | return false; 636 | } 637 | 638 | if (fwrite($this->_dHandle, $this->_buffer) !== false) { 639 | $this->_buffer = ""; 640 | 641 | return true; 642 | } else { 643 | $this->_buffer = ""; 644 | trigger_error("Error while sending message", E_USER_WARNING); 645 | 646 | return false; 647 | } 648 | } 649 | 650 | // 651 | // I/O SECTION -- {STOP} 652 | // 653 | 654 | // 655 | // INTERNAL TOOLKIT -- {START} 656 | // 657 | 658 | public function _ckOpened() 659 | { 660 | if ($this->_dState !== SERIAL_DEVICE_OPENED) { 661 | trigger_error("Device must be opened", E_USER_WARNING); 662 | 663 | return false; 664 | } 665 | 666 | return true; 667 | } 668 | 669 | public function _ckClosed() 670 | { 671 | if ($this->_dState === SERIAL_DEVICE_OPENED) { 672 | trigger_error("Device must be closed", E_USER_WARNING); 673 | 674 | return false; 675 | } 676 | 677 | return true; 678 | } 679 | 680 | public function _exec($cmd, &$out = null) 681 | { 682 | $desc = array( 683 | 1 => array("pipe", "w"), 684 | 2 => array("pipe", "w") 685 | ); 686 | 687 | $proc = proc_open($cmd, $desc, $pipes); 688 | 689 | $ret = stream_get_contents($pipes[1]); 690 | $err = stream_get_contents($pipes[2]); 691 | 692 | fclose($pipes[1]); 693 | fclose($pipes[2]); 694 | 695 | $retVal = proc_close($proc); 696 | 697 | if (func_num_args() == 2) $out = array($ret, $err); 698 | return $retVal; 699 | } 700 | 701 | // 702 | // INTERNAL TOOLKIT -- {STOP} 703 | // 704 | } 705 | -------------------------------------------------------------------------------- /PhpSerialModbus.php: -------------------------------------------------------------------------------- 1 | serial = new PhpSerial; 35 | } 36 | 37 | // Initialize serial port with specified parameters 38 | public function deviceInit($port='/dev/ttyUSB0', $baud=115200, $parity='none', $char=8, $sbits=1, $flow='none') 39 | { 40 | $this->serial->deviceSet($port); 41 | $this->serial->confBaudRate($baud); 42 | $this->serial->confParity($parity); 43 | $this->serial->confCharacterLength($char); 44 | $this->serial->confStopBits($sbits); 45 | $this->serial->confFlowControl($flow); 46 | exec('stty -F '.$port.' -brkint -icrnl -imaxbel -opost -isig -icanon -echo -echoe'); 47 | return $this->serial->_dState; 48 | } 49 | 50 | // Open serial port 51 | public function deviceOpen() 52 | { 53 | $this->serial->deviceOpen(); 54 | return $this->serial->_dState; 55 | } 56 | 57 | // Close serial port 58 | public function deviceClose() 59 | { 60 | $this->serial->deviceClose(); 61 | return $this->serial->_dState; 62 | } 63 | 64 | // Calculate CRC16 (ModBus) 65 | public function crc16($data) 66 | { 67 | $crc = 0xFFFF; 68 | for ($i = 0; $i < strlen($data); $i++) 69 | { 70 | $crc ^=ord($data[$i]); 71 | for ($j = 8; $j !=0; $j--) 72 | { 73 | if (($crc & 0x0001) !=0) 74 | { 75 | $crc >>= 1; 76 | $crc ^= 0xA001; 77 | } 78 | else 79 | $crc >>= 1; 80 | } 81 | } 82 | $highCrc=floor($crc/256); 83 | $lowCrc=($crc-$highCrc*256); 84 | return chr($lowCrc).chr($highCrc); 85 | } 86 | 87 | // Convert bin string to readable hex 88 | private function bin2hexString ($binString) 89 | { 90 | $hexString=bin2hex($binString); 91 | $hexString=chunk_split($hexString,2,"\\x"); 92 | $hexString= "\\x" . substr($hexString,0,-2); 93 | return $hexString; 94 | } 95 | 96 | public function sendRawQuery ($string, $response = true) { 97 | $this->serial->sendMessage($string); 98 | if ($this->debug) print "DEBUG [query sent]: ".$this->bin2hexString($string)."\n"; 99 | if ($response) return $this->getResponse(); else return 1; 100 | } 101 | 102 | // Send Modbus query to slave 103 | public function sendQuery ($slaveId, $functionCode, $registerAddress, $regCountOrData, $response = true) 104 | { 105 | if ( ($functionCode > 6 ) || ($functionCode < 1) ) { 106 | if ($this->debug) print "DEBUG [invalid function code]\n"; 107 | return 0; 108 | } 109 | 110 | if ($functionCode < 5) $regCountOrData = dechex($regCountOrData); 111 | 112 | $regHighByte=hexdec(substr($registerAddress,0,2)); 113 | $regLowByte=hexdec(substr($registerAddress,2)); 114 | 115 | $regCountOrData = str_pad($regCountOrData,4,"0",STR_PAD_LEFT); 116 | 117 | $rcdHighByte=hexdec(substr($regCountOrData,0,2)); 118 | $rcdLowByte=hexdec(substr($regCountOrData,2)); 119 | 120 | // Create query and convert to a binary string 121 | $query=array($slaveId, hexdec($functionCode), $regHighByte, $regLowByte, $rcdHighByte, $rcdLowByte); 122 | $queryString=implode(array_map("chr",$query)); 123 | 124 | // Calculate CRC 125 | $queryString.=$this->crc16($queryString); 126 | 127 | if ($this->debug) print "DEBUG [query sent]: ".$this->bin2hexString($queryString)."\n"; 128 | 129 | // Send over serial port 130 | $this->serial->sendMessage($queryString); 131 | 132 | if ($response) return $this->getResponse(); else return 1; 133 | } 134 | 135 | // Read response from slave 136 | public function getResponse ($raw=false,$offsetl=0,$offsetr=0) 137 | { 138 | // Time started (for timing) 139 | $startTime = microtime(true); 140 | 141 | $responseString = ''; 142 | 143 | // Allow until one second for the respone 144 | while(((microtime(true)-$startTime)<1) && ($responseString=='') ) 145 | { 146 | // Read serial port buffer (with three seconds timeout) 147 | while( ($byte = $this->serial->ReadPort()) && ((microtime(true)-$startTime)<3.0)) { 148 | $responseString=$responseString.$byte; 149 | usleep(50); 150 | } 151 | } 152 | 153 | if ($this->debug) print "DEBUG [response received]: ".$this->bin2hexString($responseString)."\n"; 154 | 155 | if ($raw) return $responseString; 156 | 157 | $stringLength=strlen($responseString); 158 | 159 | // If we have at least 5 bytes... 160 | if ($stringLength>=5) 161 | { 162 | // ...but no more than 5 163 | if ($stringLength==5) { 164 | if ($this->debug) print "DEBUG [no valid data]\n"; 165 | return 0; 166 | } 167 | 168 | // CRC Check 169 | $checkArray=(str_split($responseString,strlen($responseString)-2)); 170 | $crc=$this->crc16($checkArray[0]); 171 | if ($crc!=$checkArray[1]) { 172 | if ($this->debug) print "DEBUG [crc check failed]: (expected ".$this->bin2hexString($crc)." received ".$this->bin2hexString($checkArray[1]).")\n"; 173 | return 0; 174 | } 175 | 176 | // Convert string in array of bytes 177 | $responseArray = str_split($responseString); 178 | // This is the byte containing the numbere of data bytes 179 | $bytesNum = hexdec(bin2hex($responseArray[2])); 180 | 181 | // Create a new array with data without headers and CRC 182 | $responseData = array_slice($responseArray,3+$offsetl,$bytesNum-$offsetr); 183 | 184 | if ($this->debug) print "DEBUG [data]: ".$this->bin2hexString(implode($responseData))."\n"; 185 | 186 | // Return an array with hex data bytes 187 | return array_map("bin2hex",$responseData); 188 | } else 189 | { 190 | if ($this->debug) print "DEBUG [no response]\n"; 191 | return 0; 192 | } 193 | return 0; 194 | } 195 | } 196 | ?> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Php EpSolar Tracer Class 2 | ====== 3 | 4 | Library for communicating with Epsolar/Epever Tracer BN MPPT Solar Charger Controller 5 | 6 | Features 7 | ------- 8 | This library connects via RS485 port to the widely known Epsolar/Epever Tracer BN Series MPPT solar charger controller (like mine Tracer 2215 BN) allowing users to get data such as Battery Voltage, Load Current, Panel Power and base on the [Tracer protocol] [protocol] (Modbus). 9 | In order to get it to work you just need tu use a cheap USB/RS485 converter and connect one side to your PC/Raspberry USB port and the other to the solar charger's connector. 10 | 11 | Class methods and properties 12 | ------- 13 | For better understanding take a look at the "Quick start example" 14 | 15 | **getInfoData()** , **getRatedData()** , **getRealtimeData()** , **getStatData()** , **getSettingData()** , **getCoilData()** , **getDiscreteData()** 16 | >These functions get the various data from solar charger and put them in their rispective data arrays. The returned value is TRUE if data received or FALSE if not 17 | 18 | **$infoData** , **$ratedData** , **$realtimeData** , **$statData** , **$settingData** , **$coilData** , **$dicreteData** 19 | >These arrays are populated after calling the respective function with the data received from solar charger. The data acquired are rispectively: Info Registers, Rated Data Registers, Real-time Data/Status Registers, Statistical Data Registers, Settings Parameter Registers, Coils Registers, Discrete Input Registers. For example $realtimeData[3] could be 12.23 (Volts). These data are updated everytime you call the connected method, i.e. for updating $realtimeData you have to call getRatedData() 20 | 21 | **$infoKey** , **$ratedKey** , **$realtimeKey** , **statKey** , **$settingKey** , **$coilKey** , **$discreteKey** 22 | >These fixed arrays contains the "Key" (the label) of the specific data. For example $realtimeKey[3] is "Battery voltage" 23 | 24 | **$ratedSym** , **$realtimeSym** , **$statSym** , **$settingSym** 25 | >This fixed array contains the "Symbol" conected to the value. For example $realtimeSym[3] is "V" (Volts) 26 | 27 | 28 | Quick start example (example_cli.php) 29 | ------ 30 | This example will print all datas received from solar charger 31 | ```php 32 | getInfoData()) { 38 | print "Info Data\n"; 39 | print "----------------------------------\n"; 40 | for ($i = 0; $i < count($tracer->infoData); $i++) 41 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->infoKey[$i].": ".$tracer->infoData[$i]."\n"; 42 | } else print "Cannot get Info Data\n"; 43 | 44 | if ($tracer->getRatedData()) { 45 | print "Rated Data\n"; 46 | print "----------------------------------\n"; 47 | for ($i = 0; $i < count($tracer->ratedData); $i++) 48 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->ratedKey[$i].": ".$tracer->ratedData[$i].$tracer->ratedSym[$i]."\n"; 49 | } else print "Cannot get Rated Data\n"; 50 | 51 | if ($tracer->getRealtimeData()) { 52 | print "\nRealTime Data\n"; 53 | print "----------------------------------\n"; 54 | for ($i = 0; $i < count($tracer->realtimeData); $i++) 55 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->realtimeKey[$i].": ".$tracer->realtimeData[$i].$tracer->realtimeSym[$i]."\n"; 56 | } else print "Cannot get RealTime Data\n"; 57 | 58 | if ($tracer->getStatData()) { 59 | print "\nStatistical Data\n"; 60 | print "----------------------------------\n"; 61 | for ($i = 0; $i < count($tracer->statData); $i++) 62 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->statKey[$i].": ".$tracer->statData[$i].$tracer->statSym[$i]."\n"; 63 | } else print "Cannot get Statistical Data\n"; 64 | 65 | if ($tracer->getSettingData()) { 66 | print "\nSettings Data\n"; 67 | print "----------------------------------\n"; 68 | for ($i = 0; $i < count($tracer->settingData); $i++) 69 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->settingKey[$i].": ".$tracer->settingData[$i].$tracer->settingSym[$i]."\n"; 70 | } else print "Cannot get Settings Data\n"; 71 | 72 | if ($tracer->getCoilData()) { 73 | print "\nCoils Data\n"; 74 | print "----------------------------------\n"; 75 | for ($i = 0; $i < count($tracer->coilData); $i++) 76 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->coilKey[$i].": ".$tracer->coilData[$i]."\n"; 77 | } else print "Cannot get Coil Data\n"; 78 | 79 | if ($tracer->getDiscreteData()) { 80 | print "\nDiscrete Data\n"; 81 | print "----------------------------------\n"; 82 | for ($i = 0; $i < count($tracer->discreteData); $i++) 83 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->discreteKey[$i].": ".$tracer->discreteData[$i]."\n"; 84 | } else print "Cannot get Discrete Data\n"; 85 | ?> 86 | ``` 87 | and will produce the following output on my solar charger: 88 | 89 | ```SH 90 | Info Data 91 | ---------------------------------- 92 | 00 Manufacturer: EPsolar Tech co., Ltd 93 | 01 Model: Tracer2215BN 94 | 02 Version: V02.13+V07.24 95 | 96 | Rated Data 97 | ---------------------------------- 98 | 00 PV array rated voltage: 150V 99 | 01 PV array rated current: 20A 100 | 02 PV array rated power: 520W 101 | 03 Battery rated voltage: 24V 102 | 04 Rated charging current: 20A 103 | 05 Rated charging power: 520W 104 | 06 Charging Mode: 2 105 | 07 Rated load current: 20A 106 | 107 | RealTime Data 108 | ---------------------------------- 109 | 00 PV array voltage: 13.37V 110 | 01 PV array current: 0.01A 111 | 02 PV array power: 0.24W 112 | 03 Battery voltage: 12.34V 113 | 04 Battery charging current: 0.02A 114 | 05 Battery charging power: 0.24W 115 | 06 Load voltage: 12.34V 116 | 07 Load current: 0.64A 117 | 08 Load power: 7.89W 118 | 09 Battery temperature: 25°C 119 | 10 Charger temperature: 20.45°C 120 | 11 Heat sink temperature: 20.45°C 121 | 12 Battery SOC: 12% 122 | 13 Remote battery temperature: 25°C 123 | 14 System rated voltage: 12V 124 | 15 Battery status: 0 125 | 16 Equipment status: 11 126 | 127 | Statistical Data 128 | ---------------------------------- 129 | 00 Max input voltage today: 88.36V 130 | 01 Min input voltage today: 1.73V 131 | 02 Max battery voltage today: 15.5V 132 | 03 Min battery voltage today: 12.01V 133 | 04 Consumed energy today: 0.15KWH 134 | 05 Consumed energy this month: 2.39KWH 135 | 06 Consumed energy this year: 12.81KWH 136 | 07 Total consumed energy: 13.4KWH 137 | 08 Generated energy today: 0.26KWH 138 | 09 Generated energy this moth: 3.56KWH 139 | 10 Generated energy this year: 16.55KWH 140 | 11 Total generated energy: 17.01KWH 141 | 12 Carbon dioxide reduction: 0.01T 142 | 13 Net battery current: -0.6A 143 | 14 Battery temperature: 25°C 144 | 15 Ambient temperature: 25°C 145 | 146 | Settings Data 147 | ---------------------------------- 148 | 00 Battery type: 0 149 | 01 Battery capacity: 50Ah 150 | 02 Temperature compensation coeff.: 3mV/°C/2V 151 | 03 High voltage disconnect: 16V 152 | 04 Charging limit voltage: 15V 153 | 05 Over voltage reconnect: 15V 154 | 06 Equalization voltage: 14.6V 155 | 07 Boost voltage: 14.4V 156 | 08 Float voltage: 13.8V 157 | 09 Boost reconnect voltage: 13.2V 158 | 10 Low voltage reconnect: 12.9V 159 | 11 Under voltage recover: 12.2V 160 | 12 Under voltage warning: 12V 161 | 13 Low voltage disconnect: 11.4V 162 | 14 Discharging limit voltage: 11V 163 | 15 Realtime clock (sec): 25 164 | 16 Realtime clock (min): 26 165 | 17 Realtime clock (hour): 18 166 | 18 Realtime clock (day): 13 167 | 19 Realtime clock (month): 3 168 | 20 Realtime clock (year): 16 169 | 21 Equalization charging cycle: 30 day 170 | 22 Battery temp. warning hi limit: 65°C 171 | 23 Battery temp. warning low limit: -39.99°C 172 | 24 Controller temp. hi limit: 85°C 173 | 25 Controller temp. hi limit rec.: 75°C 174 | 26 Components temp. hi limit: 85°C 175 | 27 Components temp. hi limit rec.: 75°C 176 | 28 Line impedance: 0mOhm 177 | 29 Night Time Threshold Volt: 5V 178 | 30 Light signal on delay time: 10 min. 179 | 31 Day Time Threshold Volt: 6V 180 | 32 Light signal off delay time: 10 min. 181 | 33 Load controlling mode: 0 182 | 34 Working time length1 min.: 0 183 | 35 Working time length1 hour: 1 184 | 36 Working time length2 min.: 0 185 | 37 Working time length2 hour: 1 186 | 38 Turn on timing1 sec: 0 187 | 39 Turn on timing1 min: 0 188 | 40 Turn on timing1 hour: 19 189 | 41 Turn off timing1 sec: 0 190 | 42 Turn off timing1 min: 0 191 | 43 Turn off timing1 hour: 6 192 | 44 Turn on timing2 sec: 0 193 | 45 Turn on timing2 min: 0 194 | 46 Turn on timing2 hour: 19 195 | 47 Turn off timing2 sec: 0 196 | 48 Turn off timing2 min: 0 197 | 49 Turn off timing2 hour: 6 198 | 50 Length of night min.: 27 199 | 51 Length of night hour: 11 200 | 52 Battery rated voltage code: 0 201 | 53 Load timing control selection: 0 202 | 54 Default Load On/Off: 1 203 | 55 Equalize duration: 120 min. 204 | 56 Boost duration: 120 min. 205 | 57 Dischargning percentage: 80% 206 | 58 Charging percentage: 100% 207 | 59 Management mode: 0 208 | 209 | Coils Data 210 | ---------------------------------- 211 | 00 Manual control the load: 1 212 | 01 Enable load test mode: 0 213 | 02 Force the load on/off: 0 214 | 215 | Discrete Data 216 | ---------------------------------- 217 | 00 Over temperature inside device: 00 218 | 01 Day/Night: 00 219 | Info Data 220 | ---------------------------------- 221 | 00 Manufacturer: EPsolar Tech co., Ltd 222 | 01 Model: Tracer2215BN 223 | 02 Version: V02.13+V07.24 224 | 225 | Rated Data 226 | ---------------------------------- 227 | 00 PV array rated voltage: 150V 228 | 01 PV array rated current: 20A 229 | 02 PV array rated power: 520W 230 | 03 Battery rated voltage: 24V 231 | 04 Rated charging current: 20A 232 | 05 Rated charging power: 520W 233 | 06 Charging Mode: 2 234 | 07 Rated load current: 20A 235 | 236 | RealTime Data 237 | ---------------------------------- 238 | 00 PV array voltage: 13.39V 239 | 01 PV array current: 0.02A 240 | 02 PV array power: 0.37W 241 | 03 Battery voltage: 12.34V 242 | 04 Battery charging current: 0.03A 243 | 05 Battery charging power: 0.37W 244 | 06 Load voltage: 12.34V 245 | 07 Load current: 0.65A 246 | 08 Load power: 8.02W 247 | 09 Battery temperature: 25°C 248 | 10 Charger temperature: 20.44°C 249 | 11 Heat sink temperature: 20.44°C 250 | 12 Battery SOC: 12% 251 | 13 Remote battery temperature: 25°C 252 | 14 System rated voltage: 12V 253 | 15 Battery status: 0 254 | 16 Equipment status: 11 255 | 256 | Statistical Data 257 | ---------------------------------- 258 | 00 Max input voltage today: 88.36V 259 | 01 Min input voltage today: 1.73V 260 | 02 Max battery voltage today: 15.5V 261 | 03 Min battery voltage today: 12.01V 262 | 04 Consumed energy today: 0.15KWH 263 | 05 Consumed energy this month: 2.39KWH 264 | 06 Consumed energy this year: 12.81KWH 265 | 07 Total consumed energy: 13.4KWH 266 | 08 Generated energy today: 0.26KWH 267 | 09 Generated energy this moth: 3.56KWH 268 | 10 Generated energy this year: 16.55KWH 269 | 11 Total generated energy: 17.01KWH 270 | 12 Carbon dioxide reduction: 0.01T 271 | 13 Net battery current: -0.61A 272 | 14 Battery temperature: 25°C 273 | 15 Ambient temperature: 25°C 274 | 275 | Settings Data 276 | ---------------------------------- 277 | 00 Battery type: 0 278 | 01 Battery capacity: 50Ah 279 | 02 Temperature compensation coeff.: 3mV/°C/2V 280 | 03 High voltage disconnect: 16V 281 | 04 Charging limit voltage: 15V 282 | 05 Over voltage reconnect: 15V 283 | 06 Equalization voltage: 14.6V 284 | 07 Boost voltage: 14.4V 285 | 08 Float voltage: 13.8V 286 | 09 Boost reconnect voltage: 13.2V 287 | 10 Low voltage reconnect: 12.9V 288 | 11 Under voltage recover: 12.2V 289 | 12 Under voltage warning: 12V 290 | 13 Low voltage disconnect: 11.4V 291 | 14 Discharging limit voltage: 11V 292 | 15 Realtime clock (sec): 26 293 | 16 Realtime clock (min): 26 294 | 17 Realtime clock (hour): 18 295 | 18 Realtime clock (day): 13 296 | 19 Realtime clock (month): 3 297 | 20 Realtime clock (year): 16 298 | 21 Equalization charging cycle: 30 day 299 | 22 Battery temp. warning hi limit: 65°C 300 | 23 Battery temp. warning low limit: -39.99°C 301 | 24 Controller temp. hi limit: 85°C 302 | 25 Controller temp. hi limit rec.: 75°C 303 | 26 Components temp. hi limit: 85°C 304 | 27 Components temp. hi limit rec.: 75°C 305 | 28 Line impedance: 0mOhm 306 | 29 Night Time Threshold Volt: 5V 307 | 30 Light signal on delay time: 10 min. 308 | 31 Day Time Threshold Volt: 6V 309 | 32 Light signal off delay time: 10 min. 310 | 33 Load controlling mode: 0 311 | 34 Working time length1 min.: 0 312 | 35 Working time length1 hour: 1 313 | 36 Working time length2 min.: 0 314 | 37 Working time length2 hour: 1 315 | 38 Turn on timing1 sec: 0 316 | 39 Turn on timing1 min: 0 317 | 40 Turn on timing1 hour: 19 318 | 41 Turn off timing1 sec: 0 319 | 42 Turn off timing1 min: 0 320 | 43 Turn off timing1 hour: 6 321 | 44 Turn on timing2 sec: 0 322 | 45 Turn on timing2 min: 0 323 | 46 Turn on timing2 hour: 19 324 | 47 Turn off timing2 sec: 0 325 | 48 Turn off timing2 min: 0 326 | 49 Turn off timing2 hour: 6 327 | 50 Length of night min.: 27 328 | 51 Length of night hour: 11 329 | 52 Battery rated voltage code: 0 330 | 53 Load timing control selection: 0 331 | 54 Default Load On/Off: 1 332 | 55 Equalize duration: 120 min. 333 | 56 Boost duration: 120 min. 334 | 57 Dischargning percentage: 80% 335 | 58 Charging percentage: 100% 336 | 59 Management mode: 0 337 | 338 | Coils Data 339 | ---------------------------------- 340 | 00 Manual control the load: 1 341 | 01 Enable load test mode: 0 342 | 02 Force the load on/off: 0 343 | 344 | Discrete Data 345 | ---------------------------------- 346 | 00 Over temperature inside device: 00 347 | 01 Day/Night: 00 348 | 349 | Voltage: 12.14 350 | ``` 351 | The number at the beginning of every line rapresent the array index 352 | 353 | Note 354 | ------ 355 | If you use this class in HTTPD and not CLI don't forget to give the user the permssion to use serial port (for example with Apache on Debian: usermod -a -G dialout www-data) 356 | 357 | Contributors 358 | -------- 359 | This project is developed by Luca Soltoggio 360 | 361 | http://arduinoelectronics.wordpress.com/ ~ http://minibianpi.wordpress.com 362 | 363 | PhpSerial by Rémy Sanchez and Rizwan Kassim 364 | 365 | ## Help us 366 | 367 | If you find this project useful and would like to support its development, consider making a donation. Any contribution is greatly appreciated! 368 | 369 | **Bitcoin (BTC) Addresses:** 370 | - **1LToggio**f3rNUTCemJZSsxd1qubTYoSde6 371 | - **3LToggio**7Xx8qMsjCFfiarV4U2ZR9iU9ob 372 | 373 | License 374 | ------ 375 | Copyright (C) 2016 Luca Soltoggio 376 | 377 | This program is free software; you can redistribute it and/or modify 378 | it under the terms of the GNU General Public License as published by 379 | the Free Software Foundation; either version 2 of the License, or 380 | (at your option) any later version. 381 | 382 | This program is distributed in the hope that it will be useful, 383 | but WITHOUT ANY WARRANTY; without even the implied warranty of 384 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 385 | GNU General Public License for more details. 386 | 387 | You should have received a copy of the GNU General Public License along 388 | with this program; if not, write to the Free Software Foundation, Inc., 389 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 390 | 391 | [//]: # 392 | 393 | [protocol]: 394 | 395 | -------------------------------------------------------------------------------- /example_cli.dat: -------------------------------------------------------------------------------- 1 | Info Data 2 | ---------------------------------- 3 | 00 Manufacturer: EPsolar Tech co., Ltd 4 | 01 Model: Tracer2215BN 5 | 02 Version: V02.13+V07.24 6 | 7 | Rated Data 8 | ---------------------------------- 9 | 00 PV array rated voltage: 150V 10 | 01 PV array rated current: 20A 11 | 02 PV array rated power: 520W 12 | 03 Battery rated voltage: 24V 13 | 04 Rated charging current: 20A 14 | 05 Rated charging power: 520W 15 | 06 Charging Mode: 2 16 | 07 Rated load current: 20A 17 | 18 | RealTime Data 19 | ---------------------------------- 20 | 00 PV array voltage: 13.37V 21 | 01 PV array current: 0.01A 22 | 02 PV array power: 0.24W 23 | 03 Battery voltage: 12.34V 24 | 04 Battery charging current: 0.02A 25 | 05 Battery charging power: 0.24W 26 | 06 Load voltage: 12.34V 27 | 07 Load current: 0.64A 28 | 08 Load power: 7.89W 29 | 09 Battery temperature: 25°C 30 | 10 Charger temperature: 20.45°C 31 | 11 Heat sink temperature: 20.45°C 32 | 12 Battery SOC: 12% 33 | 13 Remote battery temperature: 25°C 34 | 14 System rated voltage: 12V 35 | 15 Battery status: 0 36 | 16 Equipment status: 11 37 | 38 | Statistical Data 39 | ---------------------------------- 40 | 00 Max input voltage today: 88.36V 41 | 01 Min input voltage today: 1.73V 42 | 02 Max battery voltage today: 15.5V 43 | 03 Min battery voltage today: 12.01V 44 | 04 Consumed energy today: 0.15KWH 45 | 05 Consumed energy this month: 2.39KWH 46 | 06 Consumed energy this year: 12.81KWH 47 | 07 Total consumed energy: 13.4KWH 48 | 08 Generated energy today: 0.26KWH 49 | 09 Generated energy this moth: 3.56KWH 50 | 10 Generated energy this year: 16.55KWH 51 | 11 Total generated energy: 17.01KWH 52 | 12 Carbon dioxide reduction: 0.01T 53 | 13 Net battery current: -0.6A 54 | 14 Battery temperature: 25°C 55 | 15 Ambient temperature: 25°C 56 | 57 | Settings Data 58 | ---------------------------------- 59 | 00 Battery type: 0 60 | 01 Battery capacity: 50Ah 61 | 02 Temperature compensation coeff.: 3mV/°C/2V 62 | 03 High voltage disconnect: 16V 63 | 04 Charging limit voltage: 15V 64 | 05 Over voltage reconnect: 15V 65 | 06 Equalization voltage: 14.6V 66 | 07 Boost voltage: 14.4V 67 | 08 Float voltage: 13.8V 68 | 09 Boost reconnect voltage: 13.2V 69 | 10 Low voltage reconnect: 12.9V 70 | 11 Under voltage recover: 12.2V 71 | 12 Under voltage warning: 12V 72 | 13 Low voltage disconnect: 11.4V 73 | 14 Discharging limit voltage: 11V 74 | 15 Realtime clock (sec): 25 75 | 16 Realtime clock (min): 26 76 | 17 Realtime clock (hour): 18 77 | 18 Realtime clock (day): 13 78 | 19 Realtime clock (month): 3 79 | 20 Realtime clock (year): 16 80 | 21 Equalization charging cycle: 30 day 81 | 22 Battery temp. warning hi limit: 65°C 82 | 23 Battery temp. warning low limit: -39.99°C 83 | 24 Controller temp. hi limit: 85°C 84 | 25 Controller temp. hi limit rec.: 75°C 85 | 26 Components temp. hi limit: 85°C 86 | 27 Components temp. hi limit rec.: 75°C 87 | 28 Line impedance: 0mOhm 88 | 29 Night Time Threshold Volt: 5V 89 | 30 Light signal on delay time: 10 min. 90 | 31 Day Time Threshold Volt: 6V 91 | 32 Light signal off delay time: 10 min. 92 | 33 Load controlling mode: 0 93 | 34 Working time length1 min.: 0 94 | 35 Working time length1 hour: 1 95 | 36 Working time length2 min.: 0 96 | 37 Working time length2 hour: 1 97 | 38 Turn on timing1 sec: 0 98 | 39 Turn on timing1 min: 0 99 | 40 Turn on timing1 hour: 19 100 | 41 Turn off timing1 sec: 0 101 | 42 Turn off timing1 min: 0 102 | 43 Turn off timing1 hour: 6 103 | 44 Turn on timing2 sec: 0 104 | 45 Turn on timing2 min: 0 105 | 46 Turn on timing2 hour: 19 106 | 47 Turn off timing2 sec: 0 107 | 48 Turn off timing2 min: 0 108 | 49 Turn off timing2 hour: 6 109 | 50 Length of night min.: 27 110 | 51 Length of night hour: 11 111 | 52 Battery rated voltage code: 0 112 | 53 Load timing control selection: 0 113 | 54 Default Load On/Off: 1 114 | 55 Equalize duration: 120 min. 115 | 56 Boost duration: 120 min. 116 | 57 Dischargning percentage: 80% 117 | 58 Charging percentage: 100% 118 | 59 Management mode: 0 119 | 120 | Coils Data 121 | ---------------------------------- 122 | 00 Manual control the load: 1 123 | 01 Enable load test mode: 0 124 | 02 Force the load on/off: 0 125 | 126 | Discrete Data 127 | ---------------------------------- 128 | 00 Over temperature inside device: 00 129 | 01 Day/Night: 00 130 | Info Data 131 | ---------------------------------- 132 | 00 Manufacturer: EPsolar Tech co., Ltd 133 | 01 Model: Tracer2215BN 134 | 02 Version: V02.13+V07.24 135 | 136 | Rated Data 137 | ---------------------------------- 138 | 00 PV array rated voltage: 150V 139 | 01 PV array rated current: 20A 140 | 02 PV array rated power: 520W 141 | 03 Battery rated voltage: 24V 142 | 04 Rated charging current: 20A 143 | 05 Rated charging power: 520W 144 | 06 Charging Mode: 2 145 | 07 Rated load current: 20A 146 | 147 | RealTime Data 148 | ---------------------------------- 149 | 00 PV array voltage: 13.39V 150 | 01 PV array current: 0.02A 151 | 02 PV array power: 0.37W 152 | 03 Battery voltage: 12.34V 153 | 04 Battery charging current: 0.03A 154 | 05 Battery charging power: 0.37W 155 | 06 Load voltage: 12.34V 156 | 07 Load current: 0.65A 157 | 08 Load power: 8.02W 158 | 09 Battery temperature: 25°C 159 | 10 Charger temperature: 20.44°C 160 | 11 Heat sink temperature: 20.44°C 161 | 12 Battery SOC: 12% 162 | 13 Remote battery temperature: 25°C 163 | 14 System rated voltage: 12V 164 | 15 Battery status: 0 165 | 16 Equipment status: 11 166 | 167 | Statistical Data 168 | ---------------------------------- 169 | 00 Max input voltage today: 88.36V 170 | 01 Min input voltage today: 1.73V 171 | 02 Max battery voltage today: 15.5V 172 | 03 Min battery voltage today: 12.01V 173 | 04 Consumed energy today: 0.15KWH 174 | 05 Consumed energy this month: 2.39KWH 175 | 06 Consumed energy this year: 12.81KWH 176 | 07 Total consumed energy: 13.4KWH 177 | 08 Generated energy today: 0.26KWH 178 | 09 Generated energy this moth: 3.56KWH 179 | 10 Generated energy this year: 16.55KWH 180 | 11 Total generated energy: 17.01KWH 181 | 12 Carbon dioxide reduction: 0.01T 182 | 13 Net battery current: -0.61A 183 | 14 Battery temperature: 25°C 184 | 15 Ambient temperature: 25°C 185 | 186 | Settings Data 187 | ---------------------------------- 188 | 00 Battery type: 0 189 | 01 Battery capacity: 50Ah 190 | 02 Temperature compensation coeff.: 3mV/°C/2V 191 | 03 High voltage disconnect: 16V 192 | 04 Charging limit voltage: 15V 193 | 05 Over voltage reconnect: 15V 194 | 06 Equalization voltage: 14.6V 195 | 07 Boost voltage: 14.4V 196 | 08 Float voltage: 13.8V 197 | 09 Boost reconnect voltage: 13.2V 198 | 10 Low voltage reconnect: 12.9V 199 | 11 Under voltage recover: 12.2V 200 | 12 Under voltage warning: 12V 201 | 13 Low voltage disconnect: 11.4V 202 | 14 Discharging limit voltage: 11V 203 | 15 Realtime clock (sec): 26 204 | 16 Realtime clock (min): 26 205 | 17 Realtime clock (hour): 18 206 | 18 Realtime clock (day): 13 207 | 19 Realtime clock (month): 3 208 | 20 Realtime clock (year): 16 209 | 21 Equalization charging cycle: 30 day 210 | 22 Battery temp. warning hi limit: 65°C 211 | 23 Battery temp. warning low limit: -39.99°C 212 | 24 Controller temp. hi limit: 85°C 213 | 25 Controller temp. hi limit rec.: 75°C 214 | 26 Components temp. hi limit: 85°C 215 | 27 Components temp. hi limit rec.: 75°C 216 | 28 Line impedance: 0mOhm 217 | 29 Night Time Threshold Volt: 5V 218 | 30 Light signal on delay time: 10 min. 219 | 31 Day Time Threshold Volt: 6V 220 | 32 Light signal off delay time: 10 min. 221 | 33 Load controlling mode: 0 222 | 34 Working time length1 min.: 0 223 | 35 Working time length1 hour: 1 224 | 36 Working time length2 min.: 0 225 | 37 Working time length2 hour: 1 226 | 38 Turn on timing1 sec: 0 227 | 39 Turn on timing1 min: 0 228 | 40 Turn on timing1 hour: 19 229 | 41 Turn off timing1 sec: 0 230 | 42 Turn off timing1 min: 0 231 | 43 Turn off timing1 hour: 6 232 | 44 Turn on timing2 sec: 0 233 | 45 Turn on timing2 min: 0 234 | 46 Turn on timing2 hour: 19 235 | 47 Turn off timing2 sec: 0 236 | 48 Turn off timing2 min: 0 237 | 49 Turn off timing2 hour: 6 238 | 50 Length of night min.: 27 239 | 51 Length of night hour: 11 240 | 52 Battery rated voltage code: 0 241 | 53 Load timing control selection: 0 242 | 54 Default Load On/Off: 1 243 | 55 Equalize duration: 120 min. 244 | 56 Boost duration: 120 min. 245 | 57 Dischargning percentage: 80% 246 | 58 Charging percentage: 100% 247 | 59 Management mode: 0 248 | 249 | Coils Data 250 | ---------------------------------- 251 | 00 Manual control the load: 1 252 | 01 Enable load test mode: 0 253 | 02 Force the load on/off: 0 254 | 255 | Discrete Data 256 | ---------------------------------- 257 | 00 Over temperature inside device: 00 258 | 01 Day/Night: 00 259 | -------------------------------------------------------------------------------- /example_cli.php: -------------------------------------------------------------------------------- 1 | getInfoData()) { 29 | print "Info Data\n"; 30 | print "----------------------------------\n"; 31 | for ($i = 0; $i < count($tracer->infoData); $i++) 32 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->infoKey[$i].": ".$tracer->infoData[$i]."\n"; 33 | } else print "Cannot get Info Data\n"; 34 | 35 | if ($tracer->getRatedData()) { 36 | print "Rated Data\n"; 37 | print "----------------------------------\n"; 38 | for ($i = 0; $i < count($tracer->ratedData); $i++) 39 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->ratedKey[$i].": ".$tracer->ratedData[$i].$tracer->ratedSym[$i]."\n"; 40 | } else print "Cannot get Rated Data\n"; 41 | 42 | if ($tracer->getRealtimeData()) { 43 | print "\nRealTime Data\n"; 44 | print "----------------------------------\n"; 45 | for ($i = 0; $i < count($tracer->realtimeData); $i++) 46 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->realtimeKey[$i].": ".$tracer->realtimeData[$i].$tracer->realtimeSym[$i]."\n"; 47 | } else print "Cannot get RealTime Data\n"; 48 | 49 | if ($tracer->getStatData()) { 50 | print "\nStatistical Data\n"; 51 | print "----------------------------------\n"; 52 | for ($i = 0; $i < count($tracer->statData); $i++) 53 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->statKey[$i].": ".$tracer->statData[$i].$tracer->statSym[$i]."\n"; 54 | } else print "Cannot get Statistical Data\n"; 55 | 56 | if ($tracer->getSettingData()) { 57 | print "\nSettings Data\n"; 58 | print "----------------------------------\n"; 59 | for ($i = 0; $i < count($tracer->settingData); $i++) 60 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->settingKey[$i].": ".$tracer->settingData[$i].$tracer->settingSym[$i]."\n"; 61 | } else print "Cannot get Settings Data\n"; 62 | 63 | if ($tracer->getCoilData()) { 64 | print "\nCoils Data\n"; 65 | print "----------------------------------\n"; 66 | for ($i = 0; $i < count($tracer->coilData); $i++) 67 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->coilKey[$i].": ".$tracer->coilData[$i]."\n"; 68 | } else print "Cannot get Coil Data\n"; 69 | 70 | if ($tracer->getDiscreteData()) { 71 | print "\nDiscrete Data\n"; 72 | print "----------------------------------\n"; 73 | for ($i = 0; $i < count($tracer->discreteData); $i++) 74 | print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->discreteKey[$i].": ".$tracer->discreteData[$i]."\n"; 75 | } else print "Cannot get Discrete Data\n"; 76 | ?> -------------------------------------------------------------------------------- /example_json.php: -------------------------------------------------------------------------------- 1 | getInfoData()) { 31 | $json->connected = true; 32 | } else { 33 | $json->connected = false; 34 | } 35 | 36 | if ($tracer->getRealtimeData()) { 37 | $json->realtime = new stdClass(); 38 | 39 | $equipStatus = $tracer->realtimeData[16]; 40 | $chargStatus = 0b11 & ($equipStatus >> 2); 41 | switch ($chargStatus) { 42 | case 0: $eStatus = "Not charging"; break; 43 | case 1: $eStatus = "Float (13.8V)"; break; 44 | case 2: $eStatus = "Boost (14.4V)"; break; 45 | case 3: $eStatus = "Equalization (14.6V)"; break; 46 | }; 47 | if ($equipStatus >> 4) { 48 | $eStatus = "Fault"; 49 | } 50 | 51 | $battStatus = $tracer->realtimeData[15]; 52 | $battLevel = 0b1111 & $battStatus; 53 | switch ($battLevel) { 54 | case 0: $bStatus = "Normal"; break; 55 | case 1: $bStatus = "Overvolt"; break; 56 | case 2: $bStatus = "Undervolt"; break; 57 | case 3: $bStatus = "Low volt disconnect"; break; 58 | case 4: { 59 | $bStatus = "FAULT"; 60 | break; 61 | } 62 | } 63 | 64 | $json->realtime->chargeCode = $chargStatus; 65 | $json->realtime->chargeStatus = $eStatus; 66 | $json->realtime->batteryCode = $battStatus; 67 | $json->realtime->batteryStatus = $bStatus; 68 | $json->realtime->batterySOC = $tracer->realtimeData[12] . "%"; 69 | $json->realtime->solarVoltage = $tracer->realtimeData[0] . "V"; 70 | $json->realtime->solarCurrent = $tracer->realtimeData[1] . "A"; 71 | $json->realtime->solarWattage = $tracer->realtimeData[2] . "W"; 72 | $json->realtime->batteryVoltage = $tracer->realtimeData[3] . "V"; 73 | $json->realtime->batteryChargingCurrent = $tracer->realtimeData[4] . "A"; 74 | $json->realtime->batteryChargingPower = $tracer->realtimeData[5] . "W"; 75 | $json->realtime->loadVoltage = $tracer->realtimeData[6] . "V"; 76 | $json->realtime->loadCurrent = $tracer->realtimeData[7] . "A"; 77 | $json->realtime->loadWattage = $tracer->realtimeData[8] . "W"; 78 | $json->realtime->temperatureBattery = $tracer->realtimeData[9] . "℃"; 79 | $json->realtime->temperatureBatteryRemote = $tracer->realtimeData[13] . "℃"; 80 | $json->realtime->temperatureCharger = $tracer->realtimeData[10] . "℃"; 81 | $json->realtime->temperatureHeatsink = $tracer->realtimeData[11] . "℃"; 82 | $json->realtime->systemRatedVoltage = $tracer->realtimeData[14] . "V"; 83 | 84 | } 85 | 86 | if ($tracer->getStatData()) { 87 | $json->stats = new stdClass(); 88 | $json->stats->maxInputVoltageToday = $tracer->statData[0] . "V"; 89 | $json->stats->minInputVoltageToday = $tracer->statData[1] . "V"; 90 | $json->stats->maxBatteryVoltageToday = $tracer->statData[2] . "V"; 91 | $json->stats->minBatteryVoltageToday = $tracer->statData[3] . "V"; 92 | $json->stats->energyConsumedDay = $tracer->statData[4] . "kWh"; 93 | $json->stats->energyConsumedMonth = $tracer->statData[5] . "kWh"; 94 | $json->stats->energyConsumedYear = $tracer->statData[6] . "kWh"; 95 | $json->stats->energyConsumedTotal = $tracer->statData[7] . "kWh"; 96 | $json->stats->energyGeneratedDay = $tracer->statData[8] . "kWh"; 97 | $json->stats->energyGeneratedMonth = $tracer->statData[9] . "kWh"; 98 | $json->stats->energyGeneratedYear = $tracer->statData[10] . "kWh"; 99 | $json->stats->energyGeneratedTotal = $tracer->statData[11] . "kWh"; 100 | $json->stats->carbonDioxideReduction = $tracer->statData[12] . "T"; 101 | $json->stats->netBatteryCurrent = $tracer->statData[13] . "A"; 102 | $json->stats->temperatureBattery = $tracer->statData[14] . "℃"; 103 | $json->stats->temperatureAmbient = $tracer->statData[15] . "℃"; 104 | 105 | } 106 | 107 | $output = json_encode($json, JSON_PRETTY_PRINT); 108 | print $output 109 | ?> -------------------------------------------------------------------------------- /example_web.php: -------------------------------------------------------------------------------- 1 | getInfoData()) { 33 | $connection="Connected"; 34 | $connection_bgcolor = "lime"; 35 | } 36 | else 37 | { 38 | $connection="Disconnected"; 39 | $connection_bgcolor = "red"; 40 | } 41 | 42 | // Get Real Time Data 43 | if ($tracer->getRealTimeData()) { 44 | $tracerstatus_bgcolor = "lime"; 45 | $equipStatus = $tracer->realtimeData[16]; 46 | $chargStatus = 0b11 & ($equipStatus >> 2); 47 | switch ($chargStatus) { 48 | case 0: $eStatus = "Not charging"; break; 49 | case 1: $eStatus = "Float (13.8V)"; break; 50 | case 2: $eStatus = "Boost (14.4V)"; break; 51 | case 3: $eStatus = "Equalization (14.6V)"; break; 52 | }; 53 | if ($equipStatus >> 4) { 54 | $eStatus = "FAULT"; 55 | $tracerstatus_bgcolor = "red"; 56 | } 57 | 58 | $battStatus = $tracer->realtimeData[15]; 59 | $battLevel = 0b1111 & $battStatus; 60 | switch ($battLevel) { 61 | case 0: $bStatus = "Normal"; break; 62 | case 1: $bStatus = "Overvolt"; break; 63 | case 2: $bStatus = "Undervolt"; break; 64 | case 3: $bStatus = "Low volt disconnect"; break; 65 | case 4: { 66 | $bStatus = "FAULT"; 67 | $tracerstatus_bgcolor = "red"; 68 | break; 69 | } 70 | } 71 | 72 | $battSoc = $tracer->realtimeData[12]; 73 | } 74 | ?> 75 | 76 | 77 | 78 | 79 | 80 | 81 | PHP EpSolar Tracer Class Web Example 82 | 83 | 84 | 195 | 196 | 197 | 198 | 199 |
200 |
201 |

PHP EpSolar Tracer Class Web Example

202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |
210 | 211 |
212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 |
-= Tracer Status =-
Battery status
Equipment status
Battery SOC
%
227 | 228 |
229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 |
-= Tracer Data =-
Battery VoltagerealtimeData[3]; ?>V
Battery CurrentrealtimeData[4]-$tracer->realtimeData[7]; ?>A
Battery PowerrealtimeData[5]-$tracer->realtimeData[8]; ?>W
Panel VoltagerealtimeData[0]; ?>V
Panel CurrentrealtimeData[1]; ?>A
Panel PowerrealtimeData[2]; ?>W
Charger temperaturerealtimeData[10]; ?>oC
256 | 257 |
258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 |
-= Tracer Info =-
ManufacturerinfoData[0]; ?>
ModelinfoData[1]; ?>
VersioninfoData[2]; ?>
273 | 274 |
275 | 276 |
277 |
278 | 279 | 280 | 281 | 282 | --------------------------------------------------------------------------------