initial commit
with fully functional worker and basic documentation
This commit is contained in:
+177
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/*
|
||||
* VE.Direct-Text-Reader
|
||||
* worker.php
|
||||
* Command line tool to fetch text protocol data from
|
||||
* VE.Direct interfaces and store it into a database
|
||||
* for further processing
|
||||
*
|
||||
* Licensed under the GPL 3.0
|
||||
* https://git.schauaus.at/VE-Tools/VE.Direct-Text-Reader
|
||||
*/
|
||||
$startAt = date('Y-m-d H:i:s');
|
||||
$scriptPath = dirname(__FILE__);
|
||||
$config = json_decode( file_get_contents($scriptPath . '/config.json') );
|
||||
|
||||
$loglevel = 0;
|
||||
switch ($config->loglevel) {
|
||||
case 'debug':
|
||||
$loglevel = 4;
|
||||
break;
|
||||
case 'info':
|
||||
$loglevel = 3;
|
||||
break;
|
||||
case 'warn':
|
||||
$loglevel = 2;
|
||||
break;
|
||||
case 'error':
|
||||
$loglevel = 1;
|
||||
break;
|
||||
}
|
||||
if ($loglevel > 0) {
|
||||
$logfile = (!str_starts_with($config->logfile, '/')) ? fopen($scriptPath . '/' . $config->logfile, 'a') : fopen($config->logfile, 'a');
|
||||
writeLog("===================================================\r\n", 1);
|
||||
writeLog("worker startet at $startAt\r\n", 1);
|
||||
writeLog("loglevel: $loglevel (" . $config->loglevel . ")\r\n\r\n", 1);
|
||||
}
|
||||
|
||||
//create database if it does not exist yet
|
||||
if(!is_file((!str_starts_with($config->database, '/')) ? $scriptPath. '/' . $config->database : $config->database)) {
|
||||
writeLog('Database not found! I will create it! ', 3);
|
||||
if( !initializeDB() ) {
|
||||
writeLog("failed! Exit!\r\n\r\n");
|
||||
cleanUp('with errors ');
|
||||
}
|
||||
else writeLog("succeess!\r\n\r\n", 3);
|
||||
}
|
||||
|
||||
$data = readData();
|
||||
if( !$data )
|
||||
cleanUp('with errors ');
|
||||
|
||||
if( !processData($data, $startAt) )
|
||||
cleanUp('with errors ');
|
||||
|
||||
cleanUp('successfully ');
|
||||
|
||||
/*
|
||||
* cleanup
|
||||
*/
|
||||
function cleanUp($status) {
|
||||
global $loglevel;
|
||||
if( $loglevel > 0) {
|
||||
global $logfile;
|
||||
writeLog('worker finished ' . $status . 'at ' . date('Y-m-d H:i:s') . "\r\n", 1);
|
||||
writeLog("===================================================\r\n\r\n", 1);
|
||||
fclose($logfile);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* global function to write new data to logifle
|
||||
*/
|
||||
function writeLog($strData, $minLogLevel) {
|
||||
global $config, $logfile, $loglevel;
|
||||
if($loglevel >= $minLogLevel)
|
||||
fwrite($logfile, $strData);
|
||||
}
|
||||
|
||||
/*
|
||||
* read data stream from VE Direct USB serial interface
|
||||
*/
|
||||
function readData() {
|
||||
global $config;
|
||||
writeLog("Open VE Direct interface:\r\n" . $config->device . "\r\n", 3);
|
||||
$VEinterface = dio_open($config->device, O_RDONLY | O_NONBLOCK);
|
||||
if($VEinterface === false) {
|
||||
writeLog("unable to open VE Direct interface!\r\n", 1);
|
||||
return false;
|
||||
}
|
||||
writeLog("success!\r\n\r\n", 3);
|
||||
|
||||
//set up the interface to properly communicate with the interface
|
||||
dio_tcsetattr( $VEinterface, array(
|
||||
'baud' => 19200,
|
||||
'bits' => 8,
|
||||
'stop' => 1,
|
||||
'parity' => 0,
|
||||
'flow_control' => 0,
|
||||
'is_canonical' => 0)
|
||||
);
|
||||
|
||||
$bytesToRead = 1024; // read 1KB by default
|
||||
if(isset($config->bytesToRead))
|
||||
$bytesToRead = $config->bytesToRead;
|
||||
writeLog("Reading $bytesToRead Byte from VE.Direct interface\r\n", 3);
|
||||
$dataStream = "";
|
||||
while(strlen($dataStream) < $bytesToRead)
|
||||
$dataStream .= dio_read($VEinterface, $bytesToRead);
|
||||
dio_close($VEinterface);
|
||||
writeLog($dataStream . "\r\n\r\n", 4);
|
||||
|
||||
//split data stream into array and remove checksums
|
||||
$dataArray = explode("\n", $dataStream);
|
||||
$collect = false;
|
||||
$returnData = array();
|
||||
|
||||
for($i=0; $i < count($dataArray); $i++) {
|
||||
if(!$collect && str_starts_with($dataArray[$i], 'PID'))
|
||||
$collect = true;
|
||||
else if($collect && str_starts_with($dataArray[$i], 'PID'))
|
||||
break;
|
||||
|
||||
if($collect) {
|
||||
$dataLine = trim($dataArray[$i]);
|
||||
if( strlen($dataLine) == 0 || str_starts_with($dataLine, 'Checksum') || str_starts_with($dataLine, ':') ) //skip empty lines and checksums
|
||||
continue;
|
||||
$dataFields = explode("\t", $dataLine);
|
||||
$returnData[$dataFields[0]] = $dataFields[1];
|
||||
}
|
||||
}
|
||||
ksort($returnData);
|
||||
writeLog("Collected data:\r\n" . print_r($returnData, true) . "\r\n", 3);
|
||||
return $returnData;
|
||||
}
|
||||
|
||||
function processData($data, $collectionDateTime) {
|
||||
global $config, $scriptPath;
|
||||
$db = (!str_starts_with($config->database, '/')) ? new SQLITE3($scriptPath . '/' . $config->database) : new SQLITE3($config->database);
|
||||
|
||||
$dbTableName = $data['PID'] . '-' . $data['SER#'];
|
||||
$sql = "SELECT name FROM sqlite_schema WHERE type='table' AND name='$dbTableName';";
|
||||
$tableNames = $db->query($sql);
|
||||
if( !$tableNames->fetchArray(SQLITE3_NUM) ) {
|
||||
writeLog('New Victron Energy Device found. Crating a new database table... ', 3);
|
||||
if( $db->exec("CREATE TABLE '$dbTableName' (date TEXT, time TEXT, data TEXT);") )
|
||||
writeLog("success!\r\n", 3);
|
||||
else {
|
||||
writeLog("failed! Cancel!\r\n", 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$dateTime = explode(" ", $collectionDateTime);
|
||||
unset($data['PID']);
|
||||
unset($data['SER#']);
|
||||
$dataJson = json_encode($data);
|
||||
|
||||
writeLog('Add dataset to database... ', 3);
|
||||
$sql = "INSERT INTO '$dbTableName' (date, time, data) VALUES('$dateTime[0]', '$dateTime[1]', '$dataJson')";
|
||||
if( !$db->exec($sql) ) {
|
||||
writeLog("failed!\r\n\r\n", 3);
|
||||
return false;
|
||||
}
|
||||
writeLog("success!\r\n\r\n", 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
function initializeDB() {
|
||||
global $config, $scriptPath;
|
||||
$dateTime = date('Y-m-d H:m:s');
|
||||
$db = (!str_starts_with($config->database, '/')) ? new SQLITE3($scriptPath . '/' . $config->database) : new SQLITE3($config->database);
|
||||
if( !$db->exec('CREATE TABLE meta (data TEXT);') ) return false;
|
||||
if( !$db->exec("INSERT INTO meta (data) VALUES ('{\"creation\": \"$dateTime\"');") ) return false;
|
||||
return true;
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user