This is an old revision of the document!


The ABRP plugin and explanations for OVMS can be found here

Beyond setting your car model with config set usr abrp.car_model <value> and personnal API token with config set usr abrp.user_token <value> you will need to change the default url with config set usr abrp.url <value>

The URL will point to code that looks a bit like this:

<?php
 
$CAR_MODEL = "kia:soul:19:64:other";
$OVMS_API_KEY = "32b2162f-9599-4647-8139-66e9f9528370";
$MY_TOKEN = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx";
$URL = "http://api.iternio.com/1/tlm/send";
 
/*
include_once('libTorque.php');
processAndSend($_SERVER['QUERY_STRING']);
*/
 
$ctx = stream_context_create(array(
    'http' => array(
        'timeout' => 1
        )
    )
);
 
file_get_contents($URL.'?'.$_SERVER['QUERY_STRING'], 0, $ctx);
 
//echo "OK!";

the libTorque.php used to be old code to parse the crazy stuff that the android Torque app used (with a Bluetooth OBD dongle)… because it started by sending data to inform on how to parse subsequent url calls… (where the ABRP plugin directly embedded in the OVMS has much easier to parse data) but at least you can start having a look:

<?php
 
global $paramMap;
 
include_once('vendor/autoload.php');
 
function processQueryString($qs){
  // userUnitXXXXXX
  // userShortNameXXXXXX
  // userFullNameXXXXXX
  // defaultUnitXXXXXX
  // kXXXXXX
  // eml / v / session / id / time
 
  $result = array();
 
  $m = new Memcached();
  $m->addServer('localhost', 11211);
 
  parse_str($qs, $queryParts);
  foreach($queryParts as $qKey => $qVal){
 
    if (preg_match("/^(eml|v|session|id)/", $qKey, $matches)) {
      //echo "elem ".$matches[1]." val: $qVal \n";
    }
    else
    if (preg_match("/^(userUnit|userShortName|userFullName|defaultUnit)([0-9A-Fa-f]{2,6})/", $qKey, $matches)) {
      //echo "elem ".$matches[1]." id (".$matches[2].") val: $qVal \n";
      //echo "memcache set : ".$matches[1]."_".$matches[2].", $qVal\n";
      $m->set($matches[1]."_".$matches[2], $qVal, 24*3600*21);
    }
    else
    if (preg_match("/^(k)([0-9A-Fa-f]{2,6})/", $qKey, $matches)) {
      //echo $matches[0]." : $qVal (".$matches[2].")\n";
      $id=$matches[2];
      if($m->get("userShortName_".$id)){
        $keyName=$m->get("userShortName_".$id);
        if (in_array($keyName,array(""))){
          $result[$keyName]=$qVal;
        } else
        if (in_array($keyName,array("Min Cell V  No.","Charging"))){
          $result[$keyName]=intval($qVal);
        } else // Default to float
          $result[$keyName]=floatval($qVal);
      }
      //echo $m->get($tag.$id)." : ".$qVal." ($id)\n";
    }
    else
    if (preg_match("/^(plop|profileName|profileFuelType|profileWeight|profileVe|profileFuelCost|\/)/", $qKey)) {
      //Discard
    }
    else
    if (preg_match("/^(time)/", $qKey)) {
      //echo "elem ".$matches[1]." val: $qVal \n";
      $result[$qKey]=intval($qVal);
    }
    else
    {
      //echo "unhandled : $qKey => $qVal\n";
    }
  }
  //var_dump($result);
  return $result;
}
 
function sendToInfluxDB($data){
  // directly get the database object
  $database = InfluxDB\Client::fromDSN(sprintf('influxdb://kiasoul:soulsoul@%s:%s/%s', "10.33.57.XX", 8086, "kiasoul64"));
  // get the client to retrieve other databases
  $client = $database->getClient();
 
  // Extract ["time"]
  if(isset($data["time"])){
    $timestamp=$data["time"]*1000;
    unset($data["time"]);
  }else return false;
 
  // Extract ["SOC Display"]
  if(isset($data["SOC Display"])){
    $SOCdisplay=$data["SOC Display"];
    //unset($data["SOC Display"]);
  }else return false;
 
  $points = [
  	new InfluxDB\Point(
  		'SOCdisplay',
  		$SOCdisplay,
  		['car' => 'joul'],
  		$data,
  		$timestamp
  	)
  ];
  $newPoints = $database->writePoints($points, InfluxDB\Database::PRECISION_MICROSECONDS);
  return $newPoints;
}
 
function processAndSend($qs){
  sendToInfluxDB( processQueryString($qs) );
}
 
function loadParamMap(){
 
}

Since, I have simply configured a NodeRed server, that consumes and parses ovms metrics over MQTT.

The nodered flow will look like this:

[
    {
        "id": "6b91f982.e7a02",
        "type": "tab",
        "label": "Kia Joul",
        "disabled": false,
        "info": ""
    },
    {
        "id": "cc30af3f.2a19b",
        "type": "mqtt in",
        "z": "6b91f982.e7a02",
        "name": "joul@mqtt",
        "topic": "joul/#",
        "qos": "2",
        "datatype": "auto",
        "broker": "a83ee8f6.376a98",
        "x": 290,
        "y": 340,
        "wires": [
            [
                "f1bcd001.877828",
                "e75ed110.0438e"
            ]
        ]
    },
    {
        "id": "f1bcd001.877828",
        "type": "debug",
        "z": "6b91f982.e7a02",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 870,
        "y": 400,
        "wires": []
    },
    {
        "id": "e75ed110.0438e",
        "type": "function",
        "z": "6b91f982.e7a02",
        "name": "mqtt2influx",
        "func": "msg.topic = msg.topic.replace(/\\//g,\"_\").replace(\"joul_\",\"\").replace(\"darthmaul_\",\"\");\n\n\nif(msg.topic.startsWith(\"metric_\")){\n    msg.topic = msg.topic.replace(\"metric_\",\"\");\n    var returnmsg = {};\n    \n    returnmsg.payload = [\n        {\n            measurement: msg.topic,\n            fields: {},\n            timestamp: new Date()\n        }\n    ];\n    \n    if(msg.payload.includes(\",\")){\n        var a = msg.payload.split(\",\"), i;\n        for (i = 0; i < a.length; i++) {\n            returnmsg.payload[0].fields[i]=parseFloat(a[i]);\n        }\n    }else{\n        returnmsg.payload[0].fields[msg.topic] = parseFloat(msg.payload);\n    }\n    \n    return returnmsg;\n}",
        "outputs": 1,
        "noerr": 0,
        "x": 530,
        "y": 520,
        "wires": [
            [
                "f1bcd001.877828",
                "d072b101.e61ea"
            ]
        ]
    },
    {
        "id": "d072b101.e61ea",
        "type": "influxdb batch",
        "z": "6b91f982.e7a02",
        "influxdb": "b0eafaa2.4c476",
        "precision": "s",
        "retentionPolicy": "",
        "name": "kiasoul@influx",
        "x": 900,
        "y": 680,
        "wires": []
    },
    {
        "id": "9eb93ce5.41b728",
        "type": "mqtt in",
        "z": "6b91f982.e7a02",
        "name": "darthmaul@mqtt",
        "topic": "darthmaul/#",
        "qos": "2",
        "datatype": "auto",
        "broker": "a83ee8f6.376a98",
        "x": 220,
        "y": 500,
        "wires": [
            [
                "e75ed110.0438e",
                "f1bcd001.877828"
            ]
        ]
    },
    {
        "id": "a83ee8f6.376a98",
        "type": "mqtt-broker",
        "z": "",
        "name": "joul",
        "broker": "10.33.57.YY",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": false,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    },
    {
        "id": "b0eafaa2.4c476",
        "type": "influxdb",
        "z": "",
        "hostname": "10.33.57.XX",
        "port": "8086",
        "protocol": "http",
        "database": "kiasoul64",
        "name": "kiasoul@influx",
        "usetls": false,
        "tls": ""
    }
]

It listens to joul/# and darthmaul/# because I ended up renaming the car after a while.

 nodered