Wednesday, 9 November 2016

Instructions for creating a dashboard to monitor your epsolar tracer setup


This is a project that I made for a Raspberry Pi (though it would work on many different platforms) so that it could record and display data from an EPSolar Tracer A Series MPPT charge controller.

The easiest way to know if you need to read further is to simply show you what it outputs (see below).


The gauges on the left show the live status, the central column shows the charging status and the charge controller temperature, and the graph to the right shows all parameters in the previous 48 hours, and is zoomable.


A simpler version is also possible using node-red as in the example below.





If you're here, I guess you're still interested so I give you much more detail and some source code.


Step by step video - note copy the fusioncharts files across at the same time I mention phpepsolartracer library being copied across.




The first thing you need is some sort of connection to the charge controller.

I have made a wireless device that plugs into the RJ45 port on the device (care none standard wiring layout) so that I can wirelessly communicate with it.

Detailed instructions for the construction of this device can be found at Colin Hickey's Youtube channel, specifically

Part 1

Part 2


Part 3


Or you can make or buy a wired connection.  Instructions for making one are given by on Adam Welche's Youtube Channel, specifically




Next you'll need a device to harvest the data, store it, and then to display it on request.

I had a Raspberry Pi from a previous project, so used that.

I installed the Raspbian operating system , specifically I installed the Jessie lite version.

Once that was working and updated I turned the Pi into a LEMP stack following these instructions.

I did deviate slightly from those instructions and changed the root path of the webserver, so when editing the Nginx configuration use the command

root /var/www/html;

instead of the path given by the instructions.  A full copy of my configuration file is given in the comments at the end of these instructions.


Nginx is the webserver running the PHP scripting language
and MySQL as the database to store the data.


The next thing to do is to connect the Pi to the solar charge controller.

Option 1
If you've got a physical wire then when you plug the USB connector into the Pi a new device appears, in my case it appears as /dev/ttyUSB0 

This connection will be useable by root, but not other users/groups, so the simplest (but most insecure) method to change this is to give full control to everyone.

sudo chmod 777 /dev/ttyUSB0

---End of Option 1---

Option 2
If you've built a wireless device then you will have configured it to a specific IP address and Port on your lan - we need to connect to it.

NB - I use the internal IP addresses of 192.168.123.10 for my Pi and 192.168.123.21 for my wireless device - use the IP addresses that are appropriate for the configuration of your lan, i.e., you will most likely have different IP addresses than those I use.


We need a piece of software called Socat to do that so at the Pi command prompt...

sudo apt-get install socat 

After it installs we need to connect socat to our device - as a naming convention I made the tty number correspond to the lan IP I was connecting to

sudo socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:WirelessDeviceIPAddress:23&

e.g.

sudo socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:192.168.123.21:23&

sudo chmod 777 /dev/ttyUSB21

---End of Option 2---


Irrespective of whether you've used Option 1 or Option 2 we need to make sure that the device is useable by non-root users, so the simplest (but most insecure) method to change this is to give full control to everyone.

So issue the command
sudo chmod 777 /dev/ttyUSB0
or
sudo chmod 777 /dev/ttyUSB21

changing the device details to those you're using

I know I've said that twice, but if you omit that stage then you can have everything set up and permissions will prevent it working.




Nearly there....
We've got a connected webserver, now we need to get the data from the charge controller and store it.

Remember we set up a mysql server, well now we need to make a database.  When you set up mysql you will have configured a root user password.

Using the tool of your choice eg command line or phpmyadmin run the following sql commands to build the database (note it will delete a table called stats in the created database if you rerun the command).

CREATE DATABASE `solardata` ;

/*Table structure for table `stats` */

DROP TABLE IF EXISTS `stats`;

CREATE TABLE `stats` (
  `Controller` int(2) NOT NULL,
  `timestamp` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
  `PV array voltage` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `PV array current` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `PV array power` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Battery voltage` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Battery charging current` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Battery charging power` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Load voltage` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Load current` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Load power` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Charger temperature` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Heat sink temperature` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Battery status` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `Equipment status` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`Controller`,`timestamp`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

I made a field Controller in the database as I may expand my system and have 2 controllers, the other fields are the ones that I chose to store from the available data from the controller - you are able to modify this as required.

We now need some PHP that speaks the same language (modbus) as our charge controller - there's a really useful library already written that does just that written by Luca Soltoggio http://arduinoelectronics.wordpress.com/ ~ http://minibianpi.wordpress.com and containing PhpSerial by Rémy Sanchez and Rizwan Kassim - the library can be downloaded from GitHub at https://github.com/toggio/PhpEpsolarTracer


Once downloaded, expand it and put it on a folder in your webserver, e.g.

mkdir /var/www/html/epsolar

and put the contents of the expanded folder into it.


Now we'll set up a script to get data from the controller and store it in the database.

Using your favorite text editor edit a file in /var/www/html/epsolar called getsolarstats.php

add the following to that file, changing 'databaseusername' and 'databasepassword' to ones that you've got set up for your database.

#!/usr/bin/php

<?php
//harvest data and stores it in a database

$dbh = new PDO("mysql:host=localhost;dbname=solardata", "databaseusername", "databasepassword");

 
//this is planning for future expansion, this array holds the wireless device connection details
$solararray = array();
$solararray["/dev/ttyUSB21"]["ip"] = '192.168.123.21';
$solararray["/dev/ttyUSB21"]["port"] = '23';

//eg expanded system with a second controller
//$solararray["/dev/ttyUSB22"]["ip"] = '192.168.123.22';
//$solararray["/dev/ttyUSB22"]["port"] = '23';


require_once 'PhpEpsolarTracer.php';

$time = time();

$i = 1;
while (list ($key, $val) = each($solararray)) {

    $tracer = new PhpEpsolarTracer($key);


    if ($tracer->getRealtimeData()) {
 
        $sth = $dbh->prepare("insert into stats (`Controller`,`timestamp`,`PV array voltage`,`PV array current`,`PV array power`,`Battery voltage`,`Battery charging current`,`Battery charging power`,`Load voltage`,`Load current`,`Load power`,`Charger temperature`, `Heat sink temperature`,`Battery status`,`Equipment status`) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
        $sth->BindParam(1, $i);
        $sth->BindParam(2, $time);
        $sth->BindParam(3, $tracer->realtimeData[0]);
        $sth->BindParam(4, $tracer->realtimeData[1]);
        $sth->BindParam(5, $tracer->realtimeData[2]);
        $sth->BindParam(6, $tracer->realtimeData[3]);
        $sth->BindParam(7, $tracer->realtimeData[4]);
        $sth->BindParam(8, $tracer->realtimeData[5]);
        $sth->BindParam(9, $tracer->realtimeData[6]);
        $sth->BindParam(10, $tracer->realtimeData[7]);
        $sth->BindParam(11, $tracer->realtimeData[8]);
        $sth->BindParam(12, $tracer->realtimeData[10]);
        $sth->BindParam(13, $tracer->realtimeData[11]);
        $sth->BindParam(14, $tracer->realtimeData[15]);
        $sth->BindParam(15, $tracer->realtimeData[16]);

        $sth->execute();

        //station id
        $i++;
    }
}
?>


Change the permissions on that script so it's runable

chmod 755 /var/www/html/epsolar/getsolarstats.php

That script should be runnable now, and will pull the data and store it in the database.  To do that automatically we can set up a cronjob - the following one will get the data every minute.

sudo crontab -e

Then add the following

* * * * * /var/www/html/epsolar/getsolarstats.php


Nearly there....  

Our data is now being stored in the database - we can display it in one of 2 ways - the first is more detailed

Method 1

For the nice gauges I used a commercial, free to use, javascript library from http://www.fusioncharts.com/ 

Download it and place it in  
/var/www/html/epsolar/fusioncharts 
so that the folder fusion charts contains four folders and index.html

Make sure it has the correct permissions using the command

chmod -R 755 /var/www/html/epsolar


And finally, here's a highly modified version of example_web.php from phpepsolartracer

Using your favorite editor make a file index.php in /var/www/html/epsolar
change /dev/ttyUSB21 and 'databaseusername' and 'databasepassword' to ones that you've used


<?php
/*
 * PHP EpSolar Tracer Class (PhpEpsolarTracer) v0.9
 *
 * Library for communicating with
 * Epsolar/Epever Tracer BN MPPT Solar Charger Controller
 *
 * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTIES !
 * USE IT AT YOUR OWN RISKS !
 *
 * Copyright (C) 2016 under GPL v. 2 license
 * 13 March 2016
 *
 * @author Luca Soltoggio
 * http://www.arduinoelettronica.com/
 * https://arduinoelectronics.wordpress.com/
 *
 * This is an example on how to use the library
 * It creates a web page with tracer data
 * 
 * The version below is a highly modified version of that referred to by the headers above, the origninal can be found at https://github.com/toggio/PhpEpsolarTracer
 */

require_once 'PhpEpsolarTracer.php';
$tracer = new PhpEpsolarTracer('/dev/ttyUSB21');

$tracerstatus_bgcolor = "#dedede";
// $ecolor = "black";
// $battSoc = 0;
// Get Info and check if is connected
if ($tracer->getInfoData()) {
    $connection = "Connected";
    $connection_bgcolor = "lime";
} else {
    $connection = "Disconnected";
    $connection_bgcolor = "red";
}

// Get Real Time Data
if ($tracer->getRealTimeData()) {
    $tracerstatus_bgcolor = "lime";
    $equipStatus = $tracer->realtimeData[16];
    $chargStatus = 0b11 & ($equipStatus >> 2);
    switch ($chargStatus) {
        case 0: $eStatus = "Not charging";
            break;
        case 1: $eStatus = "Float (13.8V)";
            break;
        case 2: $eStatus = "Boost (14.4V)";
            break;
        case 3: $eStatus = "Equalization (14.6V)";
            break;
    };
    if ($equipStatus >> 4) {
        $eStatus = "<font color=\"red\">FAULT</font>";
        $tracerstatus_bgcolor = "red";
    }

    $battStatus = $tracer->realtimeData[15];
    $battLevel = 0b1111 & $battStatus;
    switch ($battLevel) {
        case 0: $bStatus = "Normal";
            break;
        case 1: $bStatus = "<font color=\"red\">Overvolt</font>";
            break;
        case 2: $bStatus = "<font color=\"yellow\">Undervolt</font>";
            break;
        case 3: $bStatus = "<font color=\"red\">Low volt disconnect</font>";
            break;
        case 4: {
                $bStatus = "<font color=\"red\">FAULT</font>";
                $tracerstatus_bgcolor = "red";
                break;
            }
    }

    $battSoc = $tracer->realtimeData[12];
}

//get data for the last 2 weeks
//$ago = time() - 1209600;
//get data for the last 24 hrs
//$ago = time() - 86400;
//get data for the last 48 hrs
$ago = time() - (86400 * 2);
$dbh = new PDO("mysql:host=localhost;dbname=solardata", "
databaseusername", "databasepassword");
$sth = $dbh->prepare("select `timestamp`,`PV array voltage`,`PV array current`,`PV array power`,`Battery voltage`,`Battery charging current`,`Battery charging power`,`Load voltage`,`Load current`,`Load power` from stats where `Controller` = 1 and `timestamp` > ? order by `timestamp` asc");
$sth->bindParam(1, $ago);
$sth->execute();

//build the json array
$data = array();
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
    $data["category"][] = date("H:i", $row["timestamp"]);
    while (list($key, $val) = each($row)) {
        $data[$key][] = $val;
    }
}

unset($data["timestamp"]);

reset($data);
?>
<!DOCTYPE html>
<html lang="it">
    <head>
        <script type="text/javascript" src="./fusioncharts/js/fusioncharts.js"></script>
        <script type="text/javascript" src="fusioncharts/js/fusioncharts.charts.js"></script>
        <script type="text/javascript" src="fusioncharts/js/fusioncharts.widgets.js"></script>
        <script type="text/javascript" src="fusioncharts/js/themes/fusioncharts.theme.fint.js"></script>



        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'zoomlinedy',
                            renderAt: 'chart',
                            width: '800',
                            height: '600',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Performance History",
                                    "pYAxisname": "Value",
                                    "sYAxisname": "PV Array Voltage (V)",
                                    "xAxisname": "Time",
                                    "pYAxisMinValue":"0",
                                    "pYAxisMaxValue":"15",
                                    "sYAxisMaxValue": "100",
                                    "sYAxisMinValue": "0",
                                    "lineThickness": "1",
                                    "compactdatamode": "1",
                                    "dataseparator": "|",
                                    "labelHeight": "30",
                                    "theme": "fint"
                            },
                                    "categories": [{
                                    "category": "<?php
echo implode('|', $data["category"]);
unset($data["category"]);
reset($data);
?>"
                                    }],
<?php
$i = 1;
echo '"dataset":[';
while (list ($key, $val) = each($data)) {


    echo '{"seriesname": "' . $key . '",';
    if (stripos($key, 'PV array voltage') !== FALSE) {
        echo '"parentYAxis": "S",';
    } else {
        echo '"parentYAxis": "P",';
    }
    echo '"data": "' . implode('|', $val) . '"';
    echo "}";
    if ($i != count($data)) {
        echo ",";
    }

    $i++;
}
?>

                            ]
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>


        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'currentflow',
                            width: '400',
                            height: '250',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Nett Current (A)",
                                    "subcaption": "-ve = from battery | +ve = to battery ",
                                    "lowerLimit": "-30",
                                    "upperLimit": "+30",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "7",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "-30",
                                            "maxValue": "0",
                                            "code": "#e44a00"
                                    }, {
                                    "minValue": "0.001",
                                            "maxValue": "30",
                                            "code": "#6baa01"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[4] - $tracer->realtimeData[7]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'PV voltage',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "PV Voltage (V)",
                                    "lowerLimit": "0",
                                    "upperLimit": "100",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "9",
                                    "minorTMNumber": "5",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "90",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "91",
                                            "maxValue": "100",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[0]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>


        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Battery voltage',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Battery Voltage (V)",
                                    "lowerLimit": "10",
                                    "upperLimit": "15",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "7",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "10",
                                            "maxValue": "11",
                                            "code": "#e44a00"
                                    }, {
                                    "minValue": "11.001",
                                            "maxValue": "13.8",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "13.801",
                                            "maxValue": "14.5",
                                            "code": "#f8bd19"
                                    }, {
                                    "minValue": "14.501",
                                            "maxValue": "15",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[3]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Load voltage',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Load Voltage (V)",
                                    "lowerLimit": "10",
                                    "upperLimit": "15",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "16",
                                    "minorTMNumber": "5",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "13.8",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "13.801",
                                            "maxValue": "14.5",
                                            "code": "#f8bd19"
                                    }, {
                                    "minValue": "14.501",
                                            "maxValue": "15",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[6]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>


        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'PV power',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "PV power (W)",
                                    "lowerLimit": "0",
                                    "upperLimit": "400",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "5",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "350",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "351",
                                            "maxValue": "400",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[2]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>


        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Battery power',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Battery Power (W)",
                                    "lowerLimit": "0",
                                    "upperLimit": "400",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "5",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "350",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "351",
                                            "maxValue": "400",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[5]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Load power',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Load Power (W)",
                                    "lowerLimit": "0",
                                    "upperLimit": "400",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "5",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "350",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "351",
                                            "maxValue": "400",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[8]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'PV current',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "PV Current (A)",
                                    "lowerLimit": "0",
                                    "upperLimit": "30",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "4",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "25",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "25.001",
                                            "maxValue": "30",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[1]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Battery current',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Battery Current (A)",
                                    "lowerLimit": "-30",
                                    "upperLimit": "30",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "7",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "-30",
                                            "maxValue": "0",
                                            "code": "#e44a00"
                                    }, {
                                    "minValue": "0.001",
                                            "maxValue": "30",
                                            "code": "#6baa01"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[4]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>

        <script type="text/javascript">
                    FusionCharts.ready(function () {
                    var fusioncharts = new FusionCharts({
                    type: 'angulargauge',
                            renderAt: 'Load current',
                            width: '300',
                            height: '200',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Load Current (A)",
                                    "lowerLimit": "0",
                                    "upperLimit": "30",
                                    "theme": "fint",
                                    "showValue": "1",
                                    "valueBelowPivot": "1",
                                    "majorTMNumber": "4",
                                    "minorTMNumber": "9",
                            },
                                    "colorRange": {
                                    "color": [{
                                    "minValue": "0",
                                            "maxValue": "25",
                                            "code": "#6baa01"
                                    }, {
                                    "minValue": "25.001",
                                            "maxValue": "30",
                                            "code": "#e44a00"
                                    }]
                                    },
                                    "dials": {
                                    "dial": [{
                                    "value": "<?php echo $tracer->realtimeData[7]; ?>"
                                    }]
                                    }
                            }
                    }
                    );
                            fusioncharts.render();
                    });</script>


        <script type="text/javascript">
                    FusionCharts.ready(function(){
                    var fusioncharts = new FusionCharts({
                    type: 'thermometer',
                            renderAt: 'Charger temp',
                            width: '160',
                            height: '400',
                            dataFormat: 'json',
                            dataSource: {
                            "chart": {
                            "caption": "Charger Temperature",
                                    "lowerLimit": "-20",
                                    "upperLimit": "100",
                                    "numberSuffix": "°C",
                                    "showhovereffect": "1",
                                    "decimals": "2",
                                    "majorTMNumber": "13",
                                    "minorTMNumber": "5",
                                    "thmBulbRadius": "25",
                                    "thmOriginX": "80",
<?php
switch ($tracer->realtimeData[10]) {
    case ($tracer->realtimeData[10] < 10):
        echo '"gaugeFillColor": "#008ee4",';
        echo '"gaugeBorderColor": "#008ee4",';
        break;
    case ($tracer->realtimeData[10] >= 10 && $tracer->realtimeData[10] < 70):
        echo '"gaugeFillColor": "#6baa01",';
        echo '"gaugeBorderColor": "#6baa01",';
        break;
    case ($tracer->realtimeData[10] >= 70 && $tracer->realtimeData[10] < 75):
        echo '"gaugeFillColor": "#f8bd19",';
        echo '"gaugeBorderColor": "#f8bd19",';
        break;
    case ($tracer->realtimeData[10] >= 75):
        echo '"gaugeFillColor": "#e44a00",';
        echo '"gaugeBorderColor": "#e44a00",';
        break;
}
?>
                            "gaugeFillAlpha": "70",
                                    //Customizing gauge border
                                    "showGaugeBorder": "1",
                                    "gaugeBorderThickness": "2",
                                    "gaugeBorderAlpha": "60",
                                    "theme": "fint",
                                    "chartBottomMargin": "20"
                            },
                                    "value": "<?php echo $tracer->realtimeData[10]; ?>"
                            }
                    }
                    );
                            fusioncharts.render();
                    });
        </script>

        <meta charset="utf-8">
        <meta name="description" content="">
        <meta name="keywords" content="">
        <title>Power Status</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <style>
            table.gridtable {
                font-family: verdana,arial,sans-serif;
                font-size:12px;
                color:#333333;
                border-width: 1px;
                border-color: #666666;
                border-collapse: collapse;
                width: 100%;
            }
            table.gridtable th {
                border-width: 1px;
                padding: 8px;
                border-style: solid;
                border-color: #666666;
                background-color: #dedede;
                text-align: center;
            }
            table.gridtable th.connection {
                background-color: <?php echo $connection_bgcolor ?>;
                text-align:center;
            }
            table.gridtable th.tracerstatus {
                background-color: <?php echo $tracerstatus_bgcolor ?>;
                text-align:center;
            }
            table.gridtable td {
                border-width: 1px;
                border-top: 0px;
                padding: 5px;
                border-style: solid;
                border-color: #666666;
                background-color: #ffffff;
                text-align:right;
                height:17px;
            }
            table.gridtable td.bold {
                font-weight: bold;
                width: 33.3%;
                text-align:left;
            }
            table.gridtable td.head {
                font-weight: bold;
                width: 33.3%;
                text-align:right;
            }
            table.gridtable td.button {
                width: 15%;
                text-align:center;
                background-color:#efefef;
                color:#cecece;
                cursor: default;
            }
            div.centered
            {
                text-align: center;
            }
            div.inner
            {
                max-width: 650px;
                width: 95%;
                text-align: center;
                margin: 0 auto;
            }
            div.inner table
            {
                margin: 0 auto;
                text-align: left;
            }
            #chargepercentp {
                width: 100%;
                height: 100%;
                position: absolute;
                vertical-align: middle;
                left:-5px;
                z-index: 10;
            }
            #chargepercentg {
                top: 0;
                width: <?php echo $battSoc; ?>%;
                height: 100%;
                position: absolute;
                background-color:#dedede;
                margin: 0 auto;
                padding: 0;
                z-index: 1;
            }
            #container {
                position: relative;
                top: 0;
                left: 0;
                width:100%;
                height:100%;
                margin: 0 auto;
                padding: 0;
                vertical-align: middle;
                line-height: 27px;
            }
        </style>
    </head>
    <body>
        <div class="centered">
            <table style='width:97%;'>
                <tr>
                    <td>
                        <table>
                            <tr><td colspan="3" style='text-align:center;'><div id="currentflow"></div></td></tr>
                            <tr><td><div id="PV voltage"></div></td><td><div id="Battery voltage"></div></td><td><div id="Load voltage"></div></td></tr>
                            <tr><td><div id="PV current"></div></td><td><div id="Battery current"></div></td><td><div id="Load current"></div></td></tr>
                            <tr><td><div id="PV power"></div></td><td><div id="Battery power"></div></td><td><div id="Load power"></div></td></tr>
                        </table>
                    </td>
                    <td>
                        <table class="gridtable">
                            <tr>
                                <th class="tracerstatus" id="tracerstatus" colspan=2>-= Tracer Status =-</th>
                            </tr>
                            <tr>
                                <td class="bold">Battery status</td><td class="status" id="batterystatus"><?php echo $bStatus; ?></td>
                            </tr>
                            <tr>
                                <td class="bold">Equipment status</td><td class="status" id="equipmentstatus"><?php echo $eStatus; ?></td>
                            </tr>
                            <tr>
                                <td colspan="2" style='text-align:center;'><div id="Charger temp"></div></td>
                            </tr>
                        </table>
                    </td>
                    <td><div id="chart"></div></td>
                </tr>
                <tr><td colspan="3"><table class="gridtable">
                            <tr>
                                <th class="connection" id="connection"><?php echo $connection; ?></th>
                            </tr>
                        </table></td></tr>
            </table>
            <br>
        </div>
    </body>
</html>


Make sure it has the correct permissions using the command

chmod -R 755 /var/www/html/epsolar

That's it, just point a web browser to the Pi

e.g.

http://192.168.123.10/epsolar/index.php
or whatever your Pi network address is

You should see a dashboard similar to the one pictured at the top of this blog.

Mine is in development still, and I may add/remove graphs and gauges, eg I'm not sure if a nett charging gauge is needed.  I'd like to add a switch to turn on and off the load, but I've not managed to do that yet.

Things you'll want to change - each script on the page is responsible for an individual graph, and I've coloured and scaled them for my needs, you may well want to eg change the maximum deflection, and colour boundaries. Do this as required, it should be easy to identify what needs changing.

Thanks to all those that posted code and instructions that allowed me to do my little bit.

Enjoy your dashboard :)


UPDATE
I have now managed to figure out how to toggle the load - this opens up a whole raft of possibilities, including cron jobs :)


You will need to be able to issue the 'turn on load' and 'turn off load' commands.

I don't know how these commands will interact with other devices, so use at your own risk, but they work well with my 30A Tracer through the day, but at night they're not working as well, don't know if this is pv voltage related, or the low night time temperatures effecting my wireless transmitter - more investigation needed on that front.


So we need to add a couple of functions to PhpEpsolarTracer.php


    //manually turn on
    public function setLoadOn() {
        $this->tracer->sendRawQuery("\x01\x05\x00\x02\xff\x00\x2d\xfa", false);
    }

    //manually turn off
    public function setLoadOff() {
        $this->tracer->sendRawQuery("\x01\x05\x00\x02\x00\x00\x6c\x0a", false);
    }



- I added them after the function below


private function divide($a, $b) {
        return $a / $b;
    }



We'll need to add something to index.php that can handle our request to change the load status - my Pi is firewalled so there's no security to this, but don't have this publicly facing as anyone could toggle your load.


At the very top of index.php, just after


require_once 'PhpEpsolarTracer.php';
$tracer = new PhpEpsolarTracer('/dev/ttyUSB21');



add the following lines


//do this first so we can see the result in the collected data
if ($_GET["load"] == 'on') {
    $tracer->setLoadOn();
}
if ($_GET["load"] == 'off') {
    $tracer->setLoadOff();
}



That's it - just browse to your dashboard with the url


http://yourpiipaddress/epsolar/index.php?load=on


and your load will be turned on


OR


http://yourpiipaddress/epsolar/index.php?load=off


and your load will be turned off

I've added a slider to my dashboard that means I can do this automatically, and I'll be working on some additions that will mean I can easily add timed events.





Method 2

It's possible to display the data from the database in node-red.

The installation of node-red on your raspberry pi is not covered here, but you can follow the instructions given in this video to see what node-red can do and also how to install it on the raspberry pi.


One of the nice things about node-red is that it's easy to share a flow - the following uses the mysql node to get data from the database and plot it on the node-red dashboard, just copy and import the following.



[
    {
        "id": "540ef0ed.76002",
        "type": "mysql",
        "z": "41bc4e86.a2c73",
        "mydb": "4c3e4c8a.898584",
        "name": "Solardata",
        "x": 442,
        "y": 1418,
        "wires": [
            [
                "dab8ec4a.48d97"
            ]
        ]
    },
    {
        "id": "97a4a648.fd044",
        "type": "inject",
        "z": "41bc4e86.a2c73",
        "name": "",
        "topic": "SELECT SUM((SELECT `Battery voltage` FROM stats WHERE Controller = 1 ORDER BY `timestamp` DESC LIMIT 1) + (SELECT `Battery voltage` FROM stats WHERE Controller = 2 ORDER BY `timestamp` DESC LIMIT 1))/2 AS `Battery Voltage`, SUM((SELECT `Battery charging power` FROM stats WHERE Controller = 1 ORDER BY `timestamp` DESC LIMIT 1) + (SELECT `Battery charging power` FROM stats WHERE Controller = 2 ORDER BY `timestamp` DESC LIMIT 1)) AS `Battery Charging power`, SUM((SELECT `Load power` FROM stats WHERE Controller = 1 ORDER BY `timestamp` DESC LIMIT 1)) AS `Load power`",
        "payload": "",
        "payloadType": "str",
        "repeat": "60",
        "crontab": "",
        "once": true,
        "x": 209,
        "y": 1347,
        "wires": [
            [
                "540ef0ed.76002"
            ]
        ]
    },
    {
        "id": "8d0012a4.32f418",
        "type": "ui_gauge",
        "z": "41bc4e86.a2c73",
        "name": "Battery Voltage",
        "group": "9f358bc8.315728",
        "order": 1,
        "width": "6",
        "height": "6",
        "gtype": "gage",
        "title": "Battery Voltage",
        "label": "Volts",
        "format": "{{value}}",
        "min": "10",
        "max": "15",
        "colors": [
            "#b50012",
            "#00e606",
            "#ca3838"
        ],
        "seg1": "11",
        "seg2": "14.3",
        "x": 1100,
        "y": 1275,
        "wires": []
    },
    {
        "id": "143a1fa7.c76eb",
        "type": "debug",
        "z": "41bc4e86.a2c73",
        "name": "",
        "active": false,
        "console": "false",
        "complete": "false",
        "x": 1041,
        "y": 1476,
        "wires": []
    },
    {
        "id": "dab8ec4a.48d97",
        "type": "function",
        "z": "41bc4e86.a2c73",
        "name": "parse data",
        "func": "var voltage = msg.payload[0]['Battery Voltage'].toFixed(2);\nvar power = msg.payload[0]['Battery Charging power'].toFixed(2);\nvar loadpower = msg.payload[0]['Load power'].toFixed(2);\n\nmsg.topic = \"Voltage\";\nmsg.payload = voltage;\n\nvar msg1 = {topic:\"Charging Power\", payload: power};\nvar msg2 = {topic:\"Load Power\", payload: loadpower};\nvar msg3 = {topic:\"Voltage\", payload: voltage};\n\nreturn [msg, msg1, [msg1,msg2,msg3]];",
        "outputs": "3",
        "noerr": 0,
        "x": 625.9794921875,
        "y": 1332.0484619140625,
        "wires": [
            [
                "8d0012a4.32f418",
                "143a1fa7.c76eb"
            ],
            [
                "143a1fa7.c76eb",
                "b1566728.7253b"
            ],
            [
                "91e58ef9.5d602"
            ]
        ]
    },
    {
        "id": "91e58ef9.5d602",
        "type": "ui_chart",
        "z": "41bc4e86.a2c73",
        "name": "Performance",
        "group": "9f358bc8.315728",
        "order": 3,
        "width": "6",
        "height": "5",
        "label": "Recent Performance",
        "chartType": "line",
        "legend": "false",
        "xformat": "HH:mm",
        "interpolate": "linear",
        "nodata": "",
        "ymin": "0",
        "ymax": "",
        "removeOlder": "36",
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "x": 1120,
        "y": 1391,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "b1566728.7253b",
        "type": "ui_gauge",
        "z": "41bc4e86.a2c73",
        "name": "Charging Power",
        "group": "9f358bc8.315728",
        "order": 2,
        "width": "6",
        "height": "6",
        "gtype": "gage",
        "title": "Charging Power",
        "label": "Watts",
        "format": "{{value}}",
        "min": "0",
        "max": "750",
        "colors": [
            "#00e606",
            "#00e606",
            "#ca3838"
        ],
        "seg1": "",
        "seg2": "700",
        "x": 1105,
        "y": 1323,
        "wires": []
    },
    {
        "id": "4c3e4c8a.898584",
        "type": "MySQLdatabase",
        "z": "",
        "host": "192.168.123.10",
        "port": "3306",
        "db": "solardata",
        "tz": ""
    },
    {
        "id": "9f358bc8.315728",
        "type": "ui_group",
        "z": "",
        "name": "Solar Stuff",
        "tab": "ff53e552.1dc31",
        "order": 2,
        "disp": true,
        "width": "18"
    },
    {
        "id": "ff53e552.1dc31",
        "type": "ui_tab",
        "z": "",
        "name": "Home",
        "icon": "dashboard"
    }
]



When you've imported it change the topic in the inject node to

SELECT `Battery voltage` AS `Battery Voltage`,`Battery charging power`, `Load power` FROM stats ORDER BY `timestamp` DESC LIMIT 1

if you've only 1 charge controller, I run 2 and so my query was doing some maths and returning average figures.


You'll also need to update the mysql node with your database username and password.


Legal stuff

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program 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 General Public License for more details.
https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html





























75 comments:

  1. Thanks - I'm absolutely going to give this a go. Thanks for linking to my video also.

    I'll report back once I've found some time and I might be back asking for advice too! Cheers

    ReplyDelete
    Replies
    1. No problem, ask away - I learned lots from your solar videos

      Delete
  2. Hi I've followed all the instructions and i am getting the nginx default page but can't get anything else to appear. I'm not seeing anything in the error log but can see things in the access log


    192.168.0.93 - - [11/Nov/2016:10:34:02 +0000] "-" 400 0 "-" "-"
    192.168.0.93 - - [11/Nov/2016:10:34:48 +0000] "GET /phpmyadmin HTTP/1.1" 200 133 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36"
    192.168.0.93 - - [11/Nov/2016:10:34:52 +0000] "-" 400 0 "-" "-"
    192.168.0.93 - - [11/Nov/2016:10:34:52 +0000] "-" 400 0 "-" "-"
    192.168.0.93 - - [11/Nov/2016:10:35:36 +0000] "GET /epsolar/index.php HTTP/1.1" 404 133 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36"
    192.168.0.93 - - [11/Nov/2016:10:35:42 +0000] "-" 400 0 "-" "-"
    192.168.0.93 - - [11/Nov/2016:10:35:42 +0000] "-" 400 0 "-" "-"
    192.168.0.93 - - [11/Nov/2016:10:40:52 +0000] "GET /favicon.ico HTTP/1.1" 200 133 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"
    192.168.0.93 - - [11/Nov/2016:10:40:53 +0000] "GET /epsolar/index.php HTTP/1.1" 404 133 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"
    192.168.0.93 - - [11/Nov/2016:10:40:53 +0000] "GET /favicon.ico HTTP/1.1" 200 133 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"

    ReplyDelete
    Replies
    1. Colin noticed you've still not got this working. Don't think you're too far away but I'm back home tomorrow, so will post a step by step video on Friday that should hopefully get this working for you

      Delete
    2. Step by step video now available at https://www.youtube.com/watch?v=RnJiKDCugoY

      Delete
  3. Ok so you webserver is working, but the line 192.168.0.93 - - [11/Nov/2016:10:35:36 +0000] "GET /epsolar/index.php HTTP/1.1" 404 133 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36"

    Shows you're getting a file not found (404) for http://192.168.0.93/epsolar/index.php

    check to make sure that /var/www/html/epsolar/index.php exists (look for typos) and the permissions are OK for the webserver to access it, so sudo chmod -R 755 /var/www/html/epsolar should fix that.

    Then try again

    ReplyDelete
    Replies
    1. I think i'd realised that i'd blindly followed the nginx setup instructions but that is pointing to a different directory as the root location. i've changed this in the default config file but now i'm getting an error regarding internal redirection cycle. Any chance you can post your default config file for nginx.

      Delete
    2. Will do so when home (after 7pm tonight)

      Delete
  4. The contents of my /etc/nginx/sites-available/default is below

    Make changes and then retart the server with
    sudo service nginx restart

    If that was the problem I'll update my instructions - I'm used to running Apache on Debian, and the root is by default /var/www/html so I've obviously changed this and not written it down.

    ##
    # You should look at the following URL's in order to grasp a solid understanding
    # of Nginx configuration files in order to fully unleash the power of Nginx.
    # http://wiki.nginx.org/Pitfalls
    # http://wiki.nginx.org/QuickStart
    # http://wiki.nginx.org/Configuration
    #
    # Generally, you will want to move this file somewhere, and start with a clean
    # file but keep this around for reference. Or just disable in sites-enabled.
    #
    # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
    ##

    # Default server configuration
    #
    server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.php index.html index.htm index.nginx-debian.html;

    server_name 192.168.1.10;
    location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root /usr/share/nginx/html;
    }

    location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    }



    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    # include snippets/fastcgi-php.conf;
    #
    # # With php5-cgi alone:
    # fastcgi_pass 127.0.0.1:9000;
    # # With php5-fpm:
    # fastcgi_pass unix:/var/run/php5-fpm.sock;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    # deny all;
    #}
    }

    # Virtual Host configuration for example.com
    #
    # You can move that to a different file under sites-available/ and symlink that
    # to sites-enabled/ to enable it.
    #
    #server {
    # listen 80;
    # listen [::]:80;
    #
    # server_name example.com;
    #
    # root /var/www/example.com;
    # index index.html;
    #
    # location / {
    # try_files $uri $uri/ =404;
    # }
    #}


    ReplyDelete
    Replies
    1. Naturally you'll have to update the IP in that configuration too (forgot to mention that above)

      Delete
  5. Hello and thanks for sharing you project with us. I installed a quick wamp 64bit server to try to experiment your project. Still havent decided if ill go with node red or stick to simple stuff like this.

    question:
    - so im running this in windows - how do i create cronjob
    - how do i add the ip adress and port into index php - i dont seem to get anything from the device (same setup via esp01 with port23)

    Thanks in advance.

    ReplyDelete
    Replies
    1. Did it work ok for you, i was trying to install it on a few different boxes but it refused to work for myself. Think i'm doing something wrong in the LAMP setup.

      Delete
    2. hello.
      well im not super advanced in wamp but i have some experience.
      i've opened a cmd and tryied the command for the cronjob first of all before i even create it but seems the modbus file doesnt connect to port serial.
      - tryied modifing to COM07 as stated in the phpserial file and still got error not connected (same with example_web.php from github)
      what i would like to know if he used a virtual com port software for this .. or he connected directly (im shure directly but just asking)
      - one thing to try in my case anyway is to populate the database / confirm a connection - that's why i was asking how he issued the command in the index.php
      please share if you guys have anything, Thanks in advance.

      Delete
    3. update >> no socat in win/wamp :(

      Delete
    4. Hi
      I cannot give specific windows advice as I dont use it and havent done a version for it but it should work without too much tweaking. Concentrate on getting the command line example from epsolartracer php lib working and the work from there. Colin hichey has some vids about windows socat software alternatives, task scheduler could be run on windows instead of a cron job.
      Sorry for brevity but Im out of town and on a tablet

      Delete
    5. http://www.hw-group.com/products/hw_vsp/index_en.html

      If you use the software from here it allows you to setup a virtual serial port in windows, i use it for using the standard epsolar software with my home made wifi->RS485 adaptor.

      Delete
  6. hi again. thanks for your fast answer.
    ive found that php_dio might work and i have tested the extension and works. unfortunately i dont have the time.
    here the link. http://www.brainboxes.com/faq/items/how-do-i-control-a-serial-port-using-php
    i hope some more experienced coder can help the few of us,
    Thanks in advance.

    ReplyDelete
    Replies
    1. Hi
      I'm not sure that you need any further software than we've already pulled together. The phpepsolartracer library includes another library phpserial - and that works on both windows and linux machines.

      I've not tried this, but all I think you'll need to do is install a windows based mechanism for connecting to your wifi device plugged into your epsolar tracer (Colin Hichey above has videos on 2 mechanisms, one paid by Astrogeeks and a couple of free ones) on windows they will make the wifi device appear as a com port eg COM12. Then all I think you'd need to do is change any references in my codes from eg /dev/ttyUSB21 to COM12 and I **think** it should work, as looking at the code in the phpserial.php deviceSet function, it looks to work with windows.

      What you could do is - set up a connection mechanism, ignore my code for the time being, and get the communication of the phpepsolartracer library working (via COM port) with the command line script included in that library. Once that works, my code just harvest and saves it, and makes a graphical output of it.

      See how you get on.

      Delete
    2. hi, thanks for your fast answer again,

      i have constructed the same device as colin with an esp01+ttltors485 and using succesfully with the win app solar station monitor on ex,192.168.1.9 port23 -->> virtual comport 15. So the problem is not there.
      since the begining i was asking how i can name the port in your php code because everything i tryied didnt work.
      tryied COM7 , com07, \com7,\\dev\\com7 and so on.
      i understand this hasnt been done before by many ppl so not so many have the experience.

      i have already done all that. Triyed different names small or big caps .

      it is possible that im missing something but its very improbable because im watching the log files on php and apache for errors - the only thing i get is no connection.

      i was able to send hello world with the php dio extension and had a response.

      i know your code is good, i never implied otherwise, just asking for help :).
      Theres a lot of talking on the net about this project but nobody gives exact specifics.
      ill check phpserial.

      Thanks for your help. Have a happy new year.

      Delete
    3. Hi Again - OK now I understand your issue and setup a little bit better. I've not tried this on windows but it should be possible - I'll see if I can knock up a quick WAMP setup on a borrowed windows laptop and see what I find - but do feel free to try as I may not get the time.

      Happy to help, and my code is simply a quick hack I did in a couple of hours one morning, so I'm not precious about it - though I do find it useful, and on a pi or similar it means you don't need lots of electricity to run a box just to monitor your setup. My advice to ignore mine for the time being was simply to allow the underlying connection problem to be resolved, as mine just adds nice graphics while others code in the phpepsolar and phpserial and modbus libraries does the heavy lifting.

      I have a beer in my hand, so happy new year to you too :)

      Delete
    4. Had a look at this without any success I'm afraid, and am giving up on it.

      Tried dio, but while I got it to integrate (I changed a number of functions in phpSerial to use dio), I didn't have much luck, and I came across a number of bugs eg there are issues in addressing com ports > 9 syntax of \\\\.\comxx should be a work around apparently, though you can also remame them to a lower value, but the whole area of reading com ports on windows from php seems a little wobbly.

      If you're more successful than me, then please let me know.

      Delete
  7. Many thanks again for the step by step instruction, i'm up and running. I had an issue with pdo in php which took some time to sort. It's strange i had started a brand new clean installation from a new jessie image also and ran into similar issues, all good now though it's it's working ok :-)

    BTW are you from the north east of england?

    ReplyDelete
    Replies
    1. Wey Aye Bonny Lad :)

      Glad you got it sorted, the least I could do. Don't understand the PDO stuff as that video was from a vanilla Raspbian and it just worked for me.

      Run it for a couple of days and you'll see the usefulness of the 48 hour graph. I've further modified mine to store the data as this version does, but only display some of it (btw if you click on the legend you can toggle the visibility of each line). I've also now got the ability to set timers for the load. However I still have issues getting it to work reliably at night - not sure if the voltage gets low or something, as eg I cannot see the kwh data for today, this month, this year at night - but as soon as the sun comes up, this works - but I can live with it as just having the wifi data is great.

      So **thank you** as I've now made 2 of your devices, something I can do by copying, but I'd not have a clue about how to do that myself.

      Delete
  8. I'm just outside Newcastle myself, i'm about to make a second device for monitoring the output and as you say it'll prove more useful once it gets some data into it even if my panels are rather shaded in the winter :-(

    Do you mind if i pop a small vid up showing off your work and link to your video? Wanted to ask first as it's unlisted.

    ReplyDelete
    Replies
    1. The sun is below a hill at this time of year for me, so my 700W of panels are producing 6W atm. But the days are getting longer now so it should get better soon enough :)

      No problem in linking to the vid - and thank you for asking - I've made a youtube channel for my projects, but these instructions were too long to go on that channel, but I wanted to keep it separate from my quad/photography stuff, so it's unlisted - though public on this blog.

      Delete
  9. hello again and thanks for trying with win.
    eventually i found a romanian guy who made an extension phpser wich he developed specially for rs485 but seems even with that still the code needs to be adapted to work with. too many dependecies to work with at the time .

    i think ill buy a cheap pi (i have some old industrial mini pc boards but i think they draw too much and they need both 12V and 5V) i saw older ones dont draw much current - but then its more useful to implement this web solution fully .. and get rid of the esp keeping powered just 1device at5V on the charge controller or whatever supply from the main baterry bank.
    problem is time obviously i do this tests an hour per evening and somtimes extend to even03.00 in the morning being caught up in this :).
    i guess ill be trying later on .
    i was thinking tho .. when you said about php serial -> this wamp 3 64bit dont have it, infact its stated that it supports serial communication but very little.
    also php dio is made for a line of products so they designed based on the needs so well basically need to modify the whole library to work with that in windows.
    of course once that done many will use it because wamp its so fast and simple to deploy 5min and your online, many of the solar ppl i assume will run this.
    Cheers and keep it going with your projects.
    Thanks again, ill keep you posted if i discover some solution.
    Happy new year.

    http://www.thebyteworks.com/phpserial/index.html

    ReplyDelete
  10. Thanks for the link to the Digital Oceans page. I followed those instructions and I think the mysql software comments are out of date. I was not asked to select a password during installation, only if I wanted to accept the decrease in storage space that accompanies the installation. After the installation, anything and everything I tried to do regarding mysql failed, usually with a password error message.

    "To start mysqld at boot time you have to copy
    support-files/mysql.server to the right place for your system"--I have no idea what they're talking about. Can't find them.

    "pi@raspberrypi:~ $ /usr/bin/mysqladmin -u root password 'Wallaby'
    /usr/bin/mysqladmin: connect to server at 'localhost' failed
    error: 'Access denied for user 'root'@'localhost' (using password: NO)'"--typical response

    And, finally:
    "pi@raspberrypi:~ $ mysqld
    170107 12:06:59 [Warning] Using unique option prefix key_buffer instead of key_buffer_size is deprecated and will be removed in a future release. Please use the full name instead.
    170107 12:06:59 [Note] mysqld (mysqld 5.5.52-0+deb8u1) starting as process 4534 ...
    170107 12:06:59 [Warning] Can't create test file /var/lib/mysql/raspberrypi.lower-test
    170107 12:06:59 [Warning] Can't create test file /var/lib/mysql/raspberrypi.lower-test
    mysqld: Can't change dir to '/var/lib/mysql/' (Errcode: 13)
    170107 12:06:59 [ERROR] Aborting

    170107 12:06:59 [Note] mysqld: Shutdown complete"

    ReplyDelete
  11. Oh, and this:
    "pi@raspberrypi:~ $ /usr/bin/mysql_secure_installation




    NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
    SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!


    In order to log into MySQL to secure it, we'll need the current
    password for the root user. If you've just installed MySQL, and
    you haven't set the root password yet, the password will be blank,
    so you should just press enter here.

    Enter current password for root (enter for none):
    ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
    Enter current password for root (enter for none):"

    ReplyDelete
  12. hello again, and thanks for the help/updates again.
    Its Vali A. from the experimental server.
    I can provide feedback and can say i managed to work with this on a suse linux server _ alot of the problems encountered were due to inacuraccy of instruction (suse related) and permissions, lots of them.

    using suse leap 14.2 with the latest xampp instalation

    ReplyDelete
    Replies
    1. Hi

      Thanks for letting me know - not used Suse in a few years myself but think it should work on most types- it's good to hear that you've managed - hopefully you'll find it useful and can tweak it to fit your needs.

      Delete
  13. hello again,
    Question: i was looking and realized that the dials do not update as json would normally do, im missing something or this is nowrmal because its trial charts!?.
    cron job doesnt seem to do the job, tried all kind of permissions and working on an automatic script now wich should be like this:
    start cron job between 18.00 - 22.00 each 1m
    job between 22.00 - 06.00 each 5min
    job between 06.00 - 18.00 each 10sec
    using a php script for self page refresh at the moment-anyway the server is on all the time.
    i have the same problems with mysql and as ive read its a new security implemented feature some parameters need changing in some httpd/htaccess/conf files seems they are everywhere :).

    ReplyDelete
  14. Hi

    The page only displays live data when you load it. It produces JSON as this is the code that the gauges use. I could rework it to have a single page load and then poll via ajax for the data but that was overkill for my needs as I wanted to check the live data and then see if everything was in range, and review historic performance.

    To achieve what you want with the current code add

    <META HTTP-EQUIV="refresh" CONTENT="10" >

    between the <head></head> tags in index.php this will cause an automatic page refresh every 10 seconds.

    Keep in mind that the cron job running each minute is also running, so that if they both ask at the same time you will get one of the tasks missing data due to the clash.

    Permissions issues are difficult to troubleshoot, but try setting the cron jobs up as root cron jobs to see if that works for you.

    Alternatively, and probably better, run as a normal user and ensure permissions are such that that user can run the scripts.

    HTH

    ReplyDelete
  15. I am getting live data displayed but it does not seem to be writing to the database.

    In the spacge error logs I see this:
    [:error] [pid 1005] [client 192.168.1.127:51902] PHP Notice: Undefined index: category in /var/www/html/epsolar/index.php on line 140
    [Mon Jan 23 09:04:40.276994 2017] [:error] [pid 1005] PHP Warning: implode(): Invalid arguments passed in /var/www/html/epsolar/index.php on line 140

    This is line 140:
    echo implode('|', $data["category"]);

    Any help would be appreciated...

    ReplyDelete
    Replies
    1. Typo above, it should read: "In the apache error logs"
      Forgot to add the first example "getsolarstats.php" IS writing to the database without issue.

      Delete
  16. Maybe I have mis-understood how this is functioning.
    The cron job that is created is writing to the database after collecting data.
    The index.php is gathering the current data from the solar controller at the time of page load but using the data in the database to populate the history chart?

    ReplyDelete
    Replies
    1. Hi Jeremy

      Yes you've 2 different things going on here.

      The cronjob causes the harvesting of data, and storing it in a database.

      When you view the web page (index.php) live data is harvested once more, and displayed, and then a query is run on the database to return data that you've previously harvested and stored, by default I set this to two days.

      If you're pulling live data into the left side of index.php, then you only need to worry about getting something to pull the data and store and retrieve it from the database. You should concentrate on getting getsolarstats.php to run and save the data. This is covered in the video, but if you cannot get it working, just ask.

      Picking through your comments I think you mean that get solar stats is working by itself (perhaps via apache??), but not when part of a cronjob?? If that's the case then you could try making it a root cronjob, or ensuring that you can run command line php scripts - check that the syntax of the first line is getsolarstats.php has no spaces in it - I had that problem when making the installation video.


      The error message about implode not working is most likely because the script has not been able to read data from the database.

      The categories data is empty, and the implode command (joins array elements with the | delimiter) has got nothing to join together. So ensure you've got your username and password for your database set in both getsolarstats.php and index.php


      Seems you're nearly there, but not quite there - just a bit of tweaking should sort it.

      HTH



      Delete
  17. This comment has been removed by the author.

    ReplyDelete
  18. This comment has been removed by the author.

    ReplyDelete
  19. Great project!
    I Know why the first (from the video) RS485 converter do not work. It's because you need to pull up the RE/DE pins if you want to transmit (TX) and delay the pull down to allow the TX buffer to be really transmitted on the RS485. But I found a simple cheap solution that will work directly from the the esp/raspberry or arduino (5V TTL compatible) boards. Because it has a leach on the TX pin witch pull up the RE/DE pins when the TX signall is detected. And is 3.3V, so no need for dual PSUs.

    Link:
    https://www.aliexpress.com/item/R411A01-3V3-small-3-3V-Auto-RS485-to-TTL232-Converter-Board-SP3485-LvTTL-RS232-MAX3485-for/32789859586.html?spm=2114.01010208.3.2.rPd467&ws_ab_test=searchweb0_0,searchweb201602_1_10065_10068_10136_10137_10138_10060_10062_10141_10056_10055_10054_128_10059_10099_10103_10102_10096_10148_10052_10053_10050_10107_10142_10051_10143_10084_10083_10119_10080_10082_10081_10110_10111_10112_10113_10114_10037_10032_10078_10079_10077_10073_10070_10123_10120_10124,searchweb201603_9,afswitch_1_afChannel,ppcSwitch_5,single_sort_0_price_asc&btsid=c98c8cf1-47f0-4085-ad22-e2a271afb4b3&algo_expid=9769ca61-b506-4060-87be-da477e9890ac-0&algo_pvid=9769ca61-b506-4060-87be-da477e9890ac

    Question:
    If I guess correctly I just need to comment out the IP-settings and use the /dev/ttyUSBx in the code, to use the raspberry seriall port directly. Am I Right?

    ReplyDelete
    Replies
    1. In getsolarstats.php I use the key, and not the value, so yes you can add anything to this for ip and port if you're connecting directly via a wire. I did it this way to store the data outwith a database for later use elsewhere. You'll still need the socat and permissions instructions though.

      Delete
  20. Hi if you watch all the vids it was a grounding issue, the board mentioned works great.

    ReplyDelete
    Replies
    1. Hi, not the grounding problem. The board in the first video that you just mention it as not working(ebay or something).

      Delete
  21. Hi what beautiful program.

    I like to run this program on my Windows 8.1 computer. The standard program EPever is boring program and have issues.

    I have no EPSolar Tracer A Series MPPT charge controller, but the last model ET6415BND 60amp 12,24,36,48 volt

    Will this program work with my MPPT charge controller?

    ReplyDelete
    Replies
    1. Hi Lexpee

      The honest answer is I don't know.

      All of the display and storage code will work (you could install xammp or similar to set that up in a few clicks, then add the code on this blog).

      The problem would be the phpepsolar.php library (https://github.com/toggio/PhpEpsolarTracer) that I use - has to be able to speak the modbus commands that the charge controller uses. It is possible that those commands were changed between different versions of charge controller, and so the library may not be able to understand the output.

      You could do some research to find out if the modbus protocol has changed between the Tracer A and your controller, and/or you sound to have all the bits to set this up on a windows PC and could test whether the library above worked using the example script it contains (no need to make the database or my display unless you could get some output back from that example script).

      I'm not sure whether the commands issued by the software would cause your controller any problems/harm, but if eg it is compatible with an MT50 then they probably share a basic command set (I have no idea whether the MT50 is compatible with your controller though). The wiring of any lead is critical as it's non-standard and if wrong, could damage your PC and/or controller, but you sound to have a lead if you're using the official software.

      To try and look at the protocol used (using the epsolar supplied software) you could use wireshark to packet capture during communication, and see if the commands issued are the same as those the phpepsolartracer library issues - this is the method I used to figure out the commands to send to mine to turn the load off and on.

      Yours is a much more expensive controller than mine, so make sure you know what you're doing before you test/experiment as it would n't be a good place to be to issue a command that eg crashed or locked up your controller as I've no idea how tolerant/robust they are if issued non-standard commands - hardware and communications protocols aren't my area of expertise.

      If you do find out the protocols are compatible, then please feel free to let me know.






      Delete
  22. Awesome stuff, just got mine up and running this morning. I had an issue with the USB/Serial driver, but finally got around that with the instructions on the github site for the Epsolar files.

    Thanks for putting this together

    ReplyDelete
    Replies
    1. You're welcome Jeff, the positive comments appreciated. After a couple of days you should have plenty of graphs to look at - providing it's been sunny :)

      Delete
  23. Thank you very much for the hard work! I got my setup running after a struggle with the usb to RS-485 also. Its working great now thou. I have three controllers on my RS-485 network, do you think there is a way to have the data base record info from each one? I know that its asking for the info from controller address 1 right now, mine have 1,2,3 for the addressing. Ill do some digging and see if I can come up with something.

    ReplyDelete
    Replies
    1. Hi - thanks for letting me know it works - always good to hear :)

      If you get the chance, please detail the problem and solution so that it helps someone else.

      I have two controllers and record the data to the database, and 3 should be no problem.

      When I started I only had one, but planned for expansion.

      In getsolarstats.php, modify the $solararray definition to include information about all your devices.

      $solararray = array();
      $solararray["/dev/ttyUSB21"]["ip"] = '192.168.123.21';
      $solararray["/dev/ttyUSB21"]["port"] = '23';
      $solararray["/dev/ttyUSB22"]["ip"] = '192.168.123.22';
      $solararray["/dev/ttyUSB22"]["port"] = '23';


      I assume you have 3 physical usb wired connections, that's OK, just leave the port and ip values empty or dummy ie.

      $solararray = array();
      $solararray["/dev/ttyUSB21"]["ip"] = '192.168.123.21';
      $solararray["/dev/ttyUSB21"]["port"] = '23';
      $solararray["/dev/ttyUSB22"]["ip"] = '192.168.123.22';
      $solararray["/dev/ttyUSB22"]["port"] = '23';
      $solararray["/dev/ttyUSB23"]["ip"] = '192.168.123.23';
      $solararray["/dev/ttyUSB23"]["port"] = '23';

      I actually only use the $key part of the array, and the port and ip are unused (in this project).

      If I've misunderstood and you're using socat, then you will have to have multiple socat connections running, one per device. I upgraded my raspberry pi to a pi 3 B and I found such connections less reliable. - so it's a bit hacky, but every 10 minutes I kill and restart any socat processes via a cronjob - this is proven very reliable.



      You would update /dev/ttyUSB21 22 or 23 to whatever your controllers are mounted as.

      That's all you'll need to do as the harvesting loop runs through that array giving the first array member a controller_Id of 1 and then incrementing for each array member.


      Once you've got the data storing OK (should be easy) then you will have to modify the display code to either add more lines to the existing graph, or as I do, insert a new duplicate block of code to show a separate graph for each controller.

      My page is now a little different from the one on these instructions, as I do some totalling and averaging across all my controllers so I can see eg the total power production etc.

      I can post that code if of interest, or provide a little more help if you tell me what you'd like to see.

      Will not be able to reply promptly to any followup, as I'm travelling.

      Delete
    2. I am using only one USB connection, the three controllers are joined to the same rs-485 data line using a RJ-45 joiner and each controller has its own address. Device 1, Device 2 and Device 3 , I can read them all with the EPsolar PC program. If you ever use this type of setup, make sure you "DO NOT" use pins 1 and 2 that carry 12v+ power! You can cause serious damage to the controllers if these powers feed into each other. I know this after blowing up two controllers.(and then seen the warning in the protocol documents)
      I was digging into the getsolardata.php and noticed that the $i looks like the device address and it starts at 1, then at the end of the script it has an $i++ which I thought would increase the value by one. So $i would = 2 on the next time around. I don't know much about Php programming, so I don't know how the script runs again keeping the new $i value. I am going to do some more learning and digging...

      Delete
    3. Hi
      I've never used that setup, and am not sure how to address the different devices.

      You're right the $i is the first device, and it loops through the array turning the device mount point into the $key which is used to connect and get the data, when it does it stores it and then increments $i and does it again.

      So to use this approach you'd need to change the first part of the array to something that could be used to identify the mount point of each of your devices. But as I say Ive not come across your setup and don't know what that would be.

      I initially thought you'd a number of individual usb connections (which would work easily with the existing code).

      How are you getting on? - any success

      Delete
  24. Hi i just created some code which inputs the data into an influxdb which means you can then use grafana for some sweet looking and easily changable charts/dashboards. Let me know if your interested. col

    ReplyDelete
    Replies
    1. Hi Col
      Yes, by all means post the code or a link to it in these comments. Always interested to see new code. Have to say that I'm currently hooked on node-red for my dashboard. I pull the data from the database and display it on that, and I also use node-red running on the same rpi that harvests the solar data to do a number of home automation things like harvest sensor data (temp, humidity and movement) and to trigger events, eg plugs and lights going on and off. The node-red dashboard allows me to turn things on and off, and I've also included some logic so that when I'm running my inverter, it monitors my batteries and powers off my devices when they are low.

      Delete
    2. I've done a blog post about it and also popped the link to my github below.

      http://blog.eplop.co.uk/2017/06/epeverepsolar-output-to-influxdbgrafana.html

      https://github.com/chickey/Epever-influxdb

      Delete
    3. Hi Col

      I've had a look at this and it looks good, and I may use it myself in a different project.
      Thanks for letting me know.

      Delete
  25. Hi, Thanks for the basic setup, I have adjusted your code to query a new php that returns the data needed for the chart's, this allows the charts to automatically update every 5 seconds, I am also using an smart APC UPS 1500 as my inverted and have it monitoring this as well via USB, if you are interested in the code changes please let me know.

    ReplyDelete
    Replies
    1. Hi Rob Ben

      Yes by all means post the code or a link to it in these comments - one size never fits all so it gives others more options.

      Delete
  26. Great work, got mine working on the first try.

    How do you get these to autostart when rebooted?

    sudo socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:192.168.123.21:23&

    sudo chmod 777 /dev/ttyUSB21

    ReplyDelete
    Replies
    1. Hi Scott - glad you got it working.

      You've a few options, but this solution may be OK for you.

      I had an original rpi B and socat was rock solid, I upgraded to a rpi 3B and found socat often stalled, so I wrote 2 scripts and run them via cron jobs - its a bit hacky, but basically every 10 minutes I kill and restart socat.

      I don't reboot my pi often, so for me having it start within 10 minutes of a reboot is fine, so I do the following

      as root
      crontab -e

      then add the following
      */10 * * * * /home/pi/socatskill.sh
      */10 * * * * /home/pi/solarconnection.sh


      Now edit 2 scripts at the above locations
      socatskill.sh is a script that must be executable and contains the following
      #!/bin/bash
      sleep 10
      kill -9 `ps -x| grep "socat" | grep -v grep | awk '{ print $1 }'`

      solarconnections.sh is a script that must be executable and contains the following
      #!/bin/bash
      sleep 15

      socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:192.168.123.21:23&
      sleep 2
      chmod 777 /dev/ttyUSB21
      socat pty,link=/dev/ttyUSB22,unlink-close=0,raw,echo=0 tcp:192.168.123.22:23&
      sleep 2
      chmod 777 /dev/ttyUSB22


      I have 2 controllers, so miss out the lines with ttyUSB22 in them if you've got one

      The kill doesn't work well in a script (still a work in progress for me) but works from the command line better, however this means that broken or dead socat connections don't prevent me getting data as new ones are fired off periodically.

      Every couple of months or so I log in and run
      kill -9 `ps -x| grep "socat" | grep -v grep | awk '{ print $1 }'`

      from the command line and it kills all existing socat processes and I can restart them as required or wait for the cron job to fire them off.

      As I say, a bit hacky but it does work.






      Delete
    2. Forgot to add that you could run solarconnections.sh via an @reboot cron line if you didn't have any socat stability issues.

      Delete
    3. Yeah, I'm using a PI 3, so maybe the same issues. I will give your suggestions a try.

      Also, just me being lazy, I'm sure if I dig zi can find the answer. Any way to change Battery Power to Battery Temp? Battery Power just shows me the same number as PV Power.

      Delete
    4. Script seems to be keeping socat happy, time will tell.

      I figured out how to change Battery Power to Battery Temp (using remote sensor).

      Thanks again for the great work.

      Delete
  27. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi Scott

      I take it you figured it out ?

      Anyway, for others, each graph can be customised by changing eg
      the section including

      "lowerLimit": "0",
      "upperLimit": "400",
      "theme": "fint",
      "showValue": "1",
      "valueBelowPivot": "1", "majorTMNumber": "5",
      "minorTMNumber": "9",


      The colour thresholds can be changed by changing values in the
      colorRange code.

      This allows you to scale and colour the graphs for eg 12v, 24v systems etc


      Delete
  28. LOL, Yeah like 5 2 minutes after I posted.

    I also converted the example page to get some other info and called it mobile.php.

    Works great for the phone.

    I can post the code if anyone wants it

    ReplyDelete
  29. Anyone ever see their chart range on the left side have 100-800K readings?

    To fix it I just purge out the DB and all goes back to normal

    ReplyDelete
    Replies
    1. Check out your

      $ago = time() - (86400 * 2);

      line

      I provided a few options for different time periods, too much data is being returned, and deleting it just stops there being to much to be returned.

      If the

      $ago = time() - (86400 * 2);

      is 2 days as above and you get too much data back.

      Check the time on your device is correct, and the timestamps saved in the database are correct.

      Think that should help you.

      Out of contact for a few days, so good luck

      Delete
    2. Have it set for 2 day, just bumped it to 1 day for testing.

      Device time is correct (set with desktop app), PI time is correct.

      Latest timestamp in my DB reads 1499795401 I don't know how to translate that, it's 1:54 PM EST, 7/11/17

      Delete
    3. Still seeing this issue. Works great for a few days, then the chart spikes again to read 800K.

      I looked at the DB, highest number in there is 140 Watts, everything else is sub 30. If I clear the DB, It does go back to normal.....no idea on what is happening.

      Delete
    4. Can I clarify - when you say is spikes to 800k, is that the top of scale value on one of the axes? If so, which one (left or right). That should be auto scaling, but if you are getting spikes we could manually specify a max for each axis by setting the values for the max for the primary and secondary y axes - this is in the section of code

      "pYAxisMinValue":"0",
      "pYAxisMaxValue":"15", "sYAxisMaxValue": "100", "sYAxisMinValue": "0",


      So I'm not understanding how the scales go to 800k as the y axes are limited already.

      What I sometimes see is a rendering issue with the values of the lines being off, but that's caused by the 'zoom' on the line, if you select a spike region with the mouse you can zoom until you see the raw values, and any mathematical averaging on the lowest zoom of the graph is remove.

      Any help ?



      Delete
    5. Yes, it is the scale value on the left side, guess it is the auto scaling going funny.

      I will play around with it...right now it has been behaving correctly.

      Will let you know if I find anything.

      Delete
    6. I'm guessing there's a bad reading in there somewhere. What you could do next time it happens is find out where it is (I know you've checked the watts but it could be one of the other readings using the same axis).

      To avoid such spikes in the graph you could modify the query in index.php to limit all values to a known possible maximum and thereby discard any bad readings.

      ie

      $sth = $dbh->prepare("select `timestamp`,`PV array voltage`,`PV array current`,`PV array power`,`Battery voltage`,`Battery charging current`,`Battery charging power`,`Load voltage`,`Load current`,`Load power` from stats where `Controller` = 1 and `timestamp` > ? order by `timestamp` asc");

      could be modified to

      $sth = $dbh->prepare("select `timestamp`,`PV array voltage`,`PV array current`,`PV array power`,`Battery voltage`,`Battery charging current`,`Battery charging power`,`Load voltage`,`Load current`,`Load power` from stats where `Controller` = 1 and `timestamp` > ? and
      `PV array voltage` < 100 and
      `PV array current` < 100 and
      `PV array power` < 100 and
      `Battery voltage` < 100 and
      `Battery charging current` < 100 and
      `Battery charging power` < 100 and
      `Load voltage` < 100 and
      `Load current` < 100 and
      `Load power` < 100
      order by `timestamp` asc");

      changing the 100 in the above to the max value you can get for each reading in your system.

      HTH

      Delete
  30. Wonderful. Everything works well!
    wondered if there is a way to convert charger temp to Fahrenheit?
    I understand the controller outputs in Celsius.
    Just wondering.
    thanks again for your time and patience on a great project and blog!!
    John M.
    KB3ISG

    ReplyDelete
    Replies
    1. Hi John

      Glad it's working

      Changing to Fahrenheit should be easy.

      Firstly you should modify getsolarstats.php and change the lines

      $sth->BindParam(12, $tracer->realtimeData[10]);
      $sth->BindParam(13, $tracer->realtimeData[11]);

      to

      $sth->BindParam(12, (($tracer->realtimeData[10] * 1.8) + 32));
      $sth->BindParam(13, (($tracer->realtimeData[11] * 1.8) + 32));

      This will mean that the temperature in Fahrenheit will be stored in the database.


      Then search your index.php for 'thermometer'

      you should find some code that looks like


      type: 'thermometer',
      renderAt: 'Charger temp',
      width: '160',
      height: '400',
      dataFormat: 'json',
      dataSource: {
      "chart": {
      "caption": "Charger Temperature",
      "lowerLimit": "-20",
      "upperLimit": "100",
      "numberSuffix": "°C",
      "showhovereffect": "1",
      "decimals": "2",
      "majorTMNumber": "13",
      "minorTMNumber": "5",
      "thmBulbRadius": "25",
      "thmOriginX": "80",



      You will probably have to change the values of
      lowerLimit to -4
      upperLimit to 212
      numberSuffix to °F

      You may also have to change
      majorTMNumber and minorTMNumber to change the scale so it looks OK


      Save your changes and I think it should work - though I've not tried any of this code and may have made a typo.

      Naturally any Celsius values stored in your database will take a while to disappear, though you could update them with a sql command

      UPDATE stats SET `Charger temperature` = ((`Charger temperature` * 1.8) + 32), `Heat sink temperature` = ((`Heat sink temperature` * 1.8) + 32);

      Again, not tried this, so could be a syntax error.

      Travelling atm so will not be able to provide more support for a week or so.

      HTH








      Delete
    2. Thanks for such a quick response!
      I followed your suggestions and it still read in C.
      but poking around (after making a backup of things)
      modified this line in index.php under the charger temperature section:
      echo $tracer->realtimeData[10]; ?>"
      to read this way:
      echo ($tracer->realtimeData[10]*1.8+32); ?>"
      this worked for the display.
      thanks again for your help!
      John Moore
      KB3ISG

      Delete
    3. Good, I'd forgotten about the live data, and my suggestions were for the data in the database.

      Glad you got it sorted

      Delete