UPDATE
I've recently changed how I do things as I've come across this project.
I've now slightly reworked my hardware to include a wemos D1 mini with the code from the above project, and that sends me data directly to some topics on my MQTT broker - this has made things much simpler, and updates can be more frequent. I now graph that data in node-red after storing it in a database.
Note I made a change in the code detailed above in the AddressRegistry_3100 function, commenting out the original line and adding a line from an as-yes uncommitted bug fix to allow all values to be read correctly.
void AddressRegistry_3100() {
//result = node.readInputRegisters(0x3100, 10);
result = node.readInputRegisters(0x3100, 0x12);
//result = node.readInputRegisters(0x3100, 10);
result = node.readInputRegisters(0x3100, 0x12);
Original blog post below in case it helps anyone not using an MQTT broker.
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).
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).
/*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;
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.
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");
<?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';
$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++;
}
}
?>
//$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
/*
* 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>
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
No problem, ask away - I learned lots from your solar videos
ReplyDeleteHi 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
ReplyDelete192.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"
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
DeleteStep by step video now available at https://www.youtube.com/watch?v=RnJiKDCugoY
DeleteOk 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"
ReplyDeleteShows 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
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.
DeleteWill do so when home (after 7pm tonight)
DeleteThe contents of my /etc/nginx/sites-available/default is below
ReplyDeleteMake 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;
# }
#}
Naturally you'll have to update the IP in that configuration too (forgot to mention that above)
DeleteI've gone through the instructions and they're very well written but I don't get any data as a result. my USB device shows up as /dev/ttyACM0 not /Dev/ttyUSB0 I've changed what I thought needed changing based on your guide above but no data is getting to the database. Where can I look?
DeleteHi Pierre
DeleteFurther down the page at http://randomsporadicprojects.blogspot.com/2016/11/instructions-for-creating-dashboard-to_9.html?showComment=1508428670869#c1940200178123053354 I provide a link to someone who had the same issue. The device you're using is being mounted with a driver that makes it behave like a modem, which is not what you want. There seems to be an alternative driver that can be used, but the simple option taken by the last person who had this issue was to buy a different lead for about £3
HTH
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.
ReplyDeletequestion:
- 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.
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.
Deletehello.
Deletewell 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.
update >> no socat in win/wamp :(
DeleteHi
DeleteI 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
http://www.hw-group.com/products/hw_vsp/index_en.html
DeleteIf 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.
hi again. thanks for your fast answer.
ReplyDeleteive 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.
Hi
DeleteI'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.
hi, thanks for your fast answer again,
Deletei 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.
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.
DeleteHappy 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 :)
Had a look at this without any success I'm afraid, and am giving up on it.
DeleteTried 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.
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 :-)
ReplyDeleteBTW are you from the north east of england?
Wey Aye Bonny Lad :)
DeleteGlad 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.
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 :-(
ReplyDeleteDo 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.
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 :)
DeleteNo 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.
hello again and thanks for trying with win.
ReplyDeleteeventually 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
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.
ReplyDelete"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"
Oh, and this:
ReplyDelete"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):"
hello again, and thanks for the help/updates again.
ReplyDeleteIts 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
Hi
DeleteThanks 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.
hello again,
ReplyDeleteQuestion: 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 :).
Hi
ReplyDeleteThe 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
I am getting live data displayed but it does not seem to be writing to the database.
ReplyDeleteIn 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...
Typo above, it should read: "In the apache error logs"
DeleteForgot to add the first example "getsolarstats.php" IS writing to the database without issue.
Maybe I have mis-understood how this is functioning.
ReplyDeleteThe 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?
Hi Jeremy
DeleteYes 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
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteGreat project!
ReplyDeleteI 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?
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.
DeleteHi if you watch all the vids it was a grounding issue, the board mentioned works great.
ReplyDeleteHi, not the grounding problem. The board in the first video that you just mention it as not working(ebay or something).
DeleteHi what beautiful program.
ReplyDeleteI 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?
Hi Lexpee
DeleteThe 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.
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.
ReplyDeleteThanks for putting this together
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 :)
DeleteThank 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.
ReplyDeleteHi - thanks for letting me know it works - always good to hear :)
DeleteIf 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.
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)
DeleteI 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...
Hi
DeleteI'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
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
ReplyDeleteHi Col
DeleteYes, 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.
I've done a blog post about it and also popped the link to my github below.
Deletehttp://blog.eplop.co.uk/2017/06/epeverepsolar-output-to-influxdbgrafana.html
https://github.com/chickey/Epever-influxdb
Hi Col
DeleteI'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.
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.
ReplyDeleteHi Rob Ben
DeleteYes 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.
Great work, got mine working on the first try.
ReplyDeleteHow 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
Hi Scott - glad you got it working.
DeleteYou'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.
Forgot to add that you could run solarconnections.sh via an @reboot cron line if you didn't have any socat stability issues.
DeleteYeah, I'm using a PI 3, so maybe the same issues. I will give your suggestions a try.
DeleteAlso, 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.
Script seems to be keeping socat happy, time will tell.
DeleteI figured out how to change Battery Power to Battery Temp (using remote sensor).
Thanks again for the great work.
This comment has been removed by the author.
ReplyDeleteHi Scott
DeleteI 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
LOL, Yeah like 5 2 minutes after I posted.
ReplyDeleteI 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
Anyone ever see their chart range on the left side have 100-800K readings?
ReplyDeleteTo fix it I just purge out the DB and all goes back to normal
Check out your
Delete$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
Have it set for 2 day, just bumped it to 1 day for testing.
DeleteDevice 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
Still seeing this issue. Works great for a few days, then the chart spikes again to read 800K.
DeleteI 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.
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
Delete"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 ?
Yes, it is the scale value on the left side, guess it is the auto scaling going funny.
DeleteI will play around with it...right now it has been behaving correctly.
Will let you know if I find anything.
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).
DeleteTo 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
Wonderful. Everything works well!
ReplyDeletewondered 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
Hi John
DeleteGlad 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
Thanks for such a quick response!
DeleteI 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
Good, I'd forgotten about the live data, and my suggestions were for the data in the database.
DeleteGlad you got it sorted
Thank you for posting this blog and the youtube video.
ReplyDeleteI am struggling with a few things.
This is all new to me so sorry if i have missed something easy.
Should this work with the epsolar rs485 to wifi?
I have it working with the windows epsolar software with out issue but wanted a better gui with graphs like you have created here.
Problem
My sql DB does not have any data. i dont believe it is an issue accessing the DB.
the epsolar wifi dongle is on 11.11.11.254 port 8088
i have used socat and it appears to be running fine
if i "cat /dev/ttydev21" i get data but it is not readable.
Should it be?
I can ping 11.11.11.254 so i believe i am connected.
Also i have the epsolar rs485 to usb cable but when i plug that into the pi i dont get a new /dev/ttyusbx
looked for the driver and found this on github
https://github.com/kasbert/epsolar-tracer/tree/master/xr_usb_serial_common-1a
but i cant make it work. make doesnt run.
Probably just my linux skills letting me down there
everything else works
I get the graphs on my web page but as no data in the sql DB they show only default values
any help appreciated
thank you in advance
Paul
OK, I will share how I set mine up. Since my eBox could not join my network I have to "dual NIC" my PI. Wifi connected to the wifi network eBox-xxxx network on the 11.11.11.x network. My other NIC is connected to my home network.
DeleteI had to modify my getsolarstats.php to point to the 11.11.11.254 port 8088 and modify my scout to point to the same.
Hope this helps
stupid auto correct scout = socat
DeleteThanks for posting this Scott I'm sure it'll be useful for others.
DeleteHi Paul
DeleteI've been away for a few days, but I see that Scott Jones has posted some help
Have you got it working now?
Sorry looks like my earlier post did not take for some reason.
DeleteThank you scot for taking the time.
I also made those chnages in the php and socat
Can you post your getsolarstats.php (after removing password)
Is there a SQL log i could look at to see if any data is trying to be added but is being rejected?
Thanks again
Hi Colin i did translate yours project to German language. Not complete ready yet. But the page will translate automaticely back to english.
ReplyDeleteTThanks for the Great work and i will be happy to dothe grafana project as well.
In Hardware i did decide also to produce a german video how to do the hardware...
http://donau-grundel-schiff.de/2017/07/23/der-beste-universelle-solar-und-batteriemonitor-nicht-nur-fuer-boote-mit-video/
Hi Daniela
DeleteI'm a little confused as to what project you wish to incorporate - I'm guessing it's Colin's Grafana dashboard.
Any code on these pages is open source and can be included if you wanted to.
In addition to the gauges mentioned on this page - I use node-red as my dashboard too, and I've used it to logically control switches (sonoffSV relays) that work on 12-24V so that they turn on and off charging, and I'll be using them to turn on and off my inverter. I have also made a remote voltage sensor using a nodemcu chip, and a voltage divider, and I wirelessly send those readings to my raspberry pi and display them on the node-red dashboard. The node-red on my Pi will also turn on and off charging if the voltage is too low or high. This all works via the MQTT protocol.
I plan to write a blog detailing this in the relatively near future.
All my stuff is based on dry land I'm afraid :)
Hi Daniela
ReplyDeleteThis isn't Colin's blog - I just made reference to his excellent hardware solution, and he has kept me informed about his dashboard made with Grafana that you refer to - he added it to these comments so anyone interested in this area could have a look and use it if they wanted.
Thank you for posting your link here too, and your work
Hoops nice to meet you, so you do not know the background...
DeleteOk i like to integrate this project in the OpenPlotter Distribution. http://www.sailoog.com/en/openplotter
You can try it and use as Base. The Beauty is. We do not have 220V only 12V or 24V the official COM MARINE protocol is named NMEA and is closed to anyone. With the date i can put all infos in an OPEN SOURCE Server named Signal K and with this i can work free. So his work is just a general idea to go and free us from NMEA Consortium.
I need for the moment just some help. I myself go step by step, To guide users in their language. As you see everything in my blog is (badly) translate in a lot of languages.
Please help to install it on openplotter so we can grow together it to a bigger suite. Independant you have a boat or not. For the moment the automatic updates of openplotter give failures because something is wrong with yours webserver implementation. See my posting before. Next is to intercommunicate in the blogs in the comments to guide the users to the best language version.... So choose english and yours comments appear in my blog in 30 languages.
Reagards Daniela(I prefere more the real name to appear serious :-)
Just an FYI on the voltage. I am running this off-grid on the PI. I use a 12v to USB adapter to get the 5V the PI needs.
DeleteHi Colin
ReplyDeletebecause of the Webserver installation i run in major problems. It let me not do updates and upgrades!
W: Fehlschlag beim Holen von http://ppa.launchpad.net/nginx/stable/ubuntu/dists/jessie/main/binary-armhf/Packages 404 Not Found
Any solution?
Hi!
ReplyDeleteI'm new to Linux and PHP.
Is there any way to get the "index.php" file saved as a .html-file instead?
This because i would like to upload the dashboard to a webserver.
Hi Jaudao
DeleteThe scripts need to be in php format, and need to be run on something that can understand them, eg. a php enabled webserver, or command line php.
Everyone learns, and it's clear from your question that you need to understand a little better how things fit together - nothing wrong with that, we all cannot know everything.
Just to explain, the php is the program that pulls everything together, and ends up (in this case) building a web page by combining data from a database, with html, and then dynamically builds some javascript (for your web browser to run and show the graphs).
If the output of the php files were saved as html, then yes they would work on a webserver, but the pages would not update with new values from the database, ie you would get a static snapshot page.
So for this all to work, my instructions tell you how to install linux, a database, a webserver, and the php scripting language. They also give instructions on how to make the webserver able to get data from the epsolar tracer.
If you're not familiar with linux, and are familiar with windows, then it should all work there, but you'll need a different method to get the live data from the charge controller - Colin in this thread has videos on how to do that. A very easy windows installer for the webserver, database and php is xammp, you'd then just have to install the scripts and run it there.
HTH
Works great for me except one thing....stops writing data to db between sunset & sunrise, any way I could collect data 24/7 for battery monitoring??
ReplyDeleteHi James - glad it works (mostly).
DeleteWell there's nothing in the code that prevents 24 hour monitoring, and I monitor mine 24/7 - so yes there is a way :)
Guess we have to figure out how yours isn't monitoring - the only thing similar to what you're getting that I've seen is if I used the output toggling code, that worked flawlessly during daylight, but at night time caused the unit to go unresponsive - never got to the bottom of that, and ended up just not using the output toggling function - so if you've used that, then try not using it.
Otherwise can you give me a little more information on how yours is set up, did you make a wireless transmitter or do you have your pi connected by a wire?
I plan to write another blog post about my setup, and it's integrated with a lot of other stuff on my Pi, and I use node-red to automate eg, the toggling of other devices depending on voltages etc
As an alternative to the Tracer output toggle code, I use a sonoffsv controlled via MQTT (broker on pi) to toggle load and control charging - and it will turn on/off as appropriate when there's power to charge, or disconnect if the batteries are getting too low. Anyway - that's for a blog post sometime.
If you give me some idea of your configuration/setup I'll try to help.
Thanks for your reply....
DeleteI have a EPSolar Tracer4210A, hard wired as per your instructions to a pi 3 running the latest raspbian stretch.
I have everything setup as your instructions except I use apache2 instead of Nginx as I use it a lot so know apache better. I had a good look through the code & could see no reason it would not monitor 24/7 hence my query. I notice it stops when the PV is just under 14v. I have not used the output toggling function, unsure what that is as can find no code relating to toggling???
Help is much appreciated, sure its just something silly I have missed!!!
Just switched my PV off for a few minutes and it writes to db still so nothing to do with the pv dropping below 14v, will keep digging
DeleteAH HA....found it......the enter button on the front of the tracer switches the load on or off.....if the load is switched to off then I get no data to the DB when there is no PV(or under 14v), when load switched to on it writes to DB even when pv is 0v. I happened to change it this morning which is why it was still writing to db when pv switched off as per my previous message.
DeletePerfect, might help someone in the future....knew it was something silly!!!! Thank you again for an excellent tutorial & prompt help.
Excellent James thank ***you*** for posting about the output load switch needing to be on to allow night time reading.
DeleteI also don't use nginx and mostly use apache too, but was trying to keep the load light for the pi (originally wrote this for the original model B).
I have my load to permanently ON (by default) - I use switches and sonoffs after that to toggle things.
What you found is the same issue that I was having with the toggle code which I figured out to send the commands to toggle the load on and off
//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 had always thought that I had something a little wrong with this as it would work fine during the day, but not at night. Using software to toggle the load at night stopped the whole thing working for me and I thought I was crashing something.
I clearly never tried setting the load manually during my testing, and it was that, not the code that was the issue.
So the unresponsiveness at night wasn't due to the code, just simply the load needs to be on at night in order to get responses.
Very useful info, and thanks for posting it here - bound to help someone out.
Best regards
An answer to what I imagine to be a scratching your head time!! My curiosity asks why does it stop data when in the off position?? There must be a switch or something that tells it to stop when off so must be a way to tell it to continue instead. I too will be using switches and sonoffs but the query remains...why?? At least you now know its not your code!!
DeleteHi,
DeleteI've been trying to make this work and it seems that the "load off" is not the problem.
It really looks like the code is preventing further reading after "load on" OR "load off" command.
I'll try to explain :
When the load is "on" and I switch it "off" with the portion of code you gave it will prevent further reading if at night like you said.
BUT, if I manually (button) switch the load off I can still monitor data.
So my conclusion is that it come from the code don't you think ?
Any ideas ?
Reverse operation also crash it :
DeleteIf load if off and I turn it on with the php code, it will crash and prevent further reading...
Hi Guillaum
DeleteI never did get to the bottom of this - though it works fine with a PV voltage above 14V, ie through the day I never got it to work well at night. The codes that I mention above were worked out using Wireshark to see what was being sent, and then putting them into php code
The load off that James above was mentioning isn't the issue for the toggling, it was something that prevented him from getting data at intervals overnight, once in the off position, he was unable to get eg voltage updates, however if he manually pressed the button, he was able to get data throughout the night.
Below is my best guess
It may be that keeping the load on energises something, allowing it to respond to requests for data. If the load is off, but the PV voltage is > 14 then whatever needs power is able to get it from the PV side, once the voltage drops below 14V, there isn't sufficient power for that component to either output readings, or respond to toggle requests.
I've not looked at this in over a year, and cannot remember if I ran the official software at night to see how it behaved then - but even if it did that would be via a laptop, and perhaps not have the same power requirements as the wifi transmitter so may not be conclusive.
hi can you make a new article how you set up this with node red and mqtt in details. i like to start with it but do not understand how it works. Thanks
ReplyDeleteStep by step...
Hi Daniela
DeleteThat's on my to-do list, but cannot promise when it will happen, as I've a number of projects on the go.
Now that it's not sunny here (autumn has arrived) I'm reconfiguring my system to 24V, and as a consequence I'll be rewriting my node-red flows to make it behave as I want. I will have a hybrid lead acid and diy lipo 3kWh powerwall system which I've just about finished building and I'll be using flows to manage the charging of each of my storage mechanisms, and toggling an inverter remotely - and also using it to disconnect etc on low/high voltages. I'm probably going to write a long article/series of articles on this detailing how it's all set up and configured.
However, in the meantime - if you follow the instruction in the video on node-red that I link to above, it does walk you through the installation process (I initially used it to first set up my system - with a lot of pausing to note the commands used).
After you get an install working, you can head off to BRUH Automation https://www.youtube.com/watch?v=-JxPWA-qxAk&t=796s where there's a really good video on installing custom firmware on your sonoff - and he has lots of other similar interesting videos.
There's even an online version of node-red that you can set up a free account with and have a play with it to get an understanding of how it works.
https://fred.sensetecnic.com/
HTH
Hi, this project looks really good and I am trying to replicate it but have run into a snag. I have solar panels on my narrowboat and use an Epsolar BN mppt controller. I have the epsolar remote monitor and the usb comms cable supplied with it. It all works and when connected to a windows pc, the control software works so I know that all of the hardware works. I set up LEMP on a pi3 running the last version of Jessie before Stretch was released.
ReplyDeleteThe problem that I have is that the pi doesn't give the connection a ttyUSB name, it calls it ttyACM0. As you can see from the following, the pi seems to identify the device correctly. I tried setting the permissions for ttyACM0 as you described for ttyUSB0 but got an error. In the PHP code, I used ttyACM0 instead of ttyUSB0 but when navigate to index.php I get a 500 error. The database isn't populating either. So although the pi knows that the interface is there I am unable to address it, can you help?
I've pasted various bits of info from the pi, maybe there's something in there that means something to you.
George
Hi George
DeleteI'll try to help but I have to admit that this is outwith my normal scope, so I'm definitely at the edge of my 'performance envelope' here.
First thing I have to say is that I don't know if the php library I use for modbus communication works with the Epsolar BN controller (though I think people have successfully connected to them) - their modbus implementation may be different to the tracer A.
However I think what's happening is that the driver you're pi is using is the generic one that handles your connector in a manner that makes it behave like a modem, rather than a driver that makes it work like a usb device.
A bit of googling got me here https://github.com/kasbert/epsolar-tracer
This looks to contain a driver that you can use that will mount your device so that it's handled like a usb device, and will appear as ttyxRUSB0
device which may work with the software as you've tried to do ie replace ttyUSB0 with ttyxRUSB0 throughout. Not you have to compile the new kernel module, and disable the acm one for this to work.
The link above then manages to connect with a python script. As the page seems to be for Tracer A and BN, it make me thing the modbus may be the same, and therefore, this dashboard, and the phplibrary it uses may work.
I think this should get you connected from a pi, either with my dashboard, or at the very least with a pythons script.
If you give it a go, and it works, could you post here and let others know please?
Cheers
Hi, thanks for the reply. I decided to take the easy way out and buy the RS485 usb adapter which shows up as ttyUSB0 when I plug it into the pi. I guess that the epever windows software is doing a lot of the work when connected with the simple cable and at one time I would have persevered to try and make the cable work with Linux just for the hell of it. Laziness and a UK supplier of the USB adapter at £2.99 means that I should be able to replicate you setup on the boat. After that, I am hoping to tap into the Mastervolt masterbus equipment on board. It is a canbus system but unfortunately Mastervolt are very secretive about their code so there will be a fair bit of work to do. They do sell an opencan interface but it costs over £400 and probably costs about £5 to produce!
DeleteThanks again for producing a brilliant project.
For £2.99 I'd have done the same :)
DeleteDon't know anything about Mastervolt, but I've done a fair bit of googling in my time and have found that most of the answers are out there, sometimes they take a bit of work, but these days it's amazing what you can do with hardware for a few pounds and some open source software.
I'm busy preparing some more blogs with some node-red automation detailed that may be of interest to boat dwellers, so please feel free to call by here occassionally. Having spent a few holidays on narrow boats I've a yearning in that direction, though I have to admit to being far too messy to consider it for anything other than a holiday.
It's a project that I had the skills and interest to perform, and I'm glad it's of use to others.
Cheers
Andrew
If you still have the other tracer USB cable, I got mine running using the github drivers. The problem with github is they assume that you already have the kernel headers installed which the Pi doesn't by default. you need to install the headers using sudo apt-get install raspberrypi-kernel-headers, then run the make and insmod commands. I also copied the resuolting *.ko file into the modules folder and added an endtry into the modules file. You'll also need to blacklist the ACM driver to keep it from installing.
Delete[ 2.290337] usb 1-1.3: New USB device found, idVendor=04e2, idProduct=1411
ReplyDelete[ 2.290347] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2.290354] usb 1-1.3: Product: XR21B1411
[ 2.290363] usb 1-1.3: Manufacturer: Exar Corp.
[ 2.290370] usb 1-1.3: SerialNumber: G8495319441
[ 2.813480] systemd-udevd[147]: starting version 215
[ 3.097678] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
[ 3.098757] usbcore: registered new interface driver cdc_acm
[ 3.098770] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ 3.170159] gpiomem-bcm2835 3f200000.gpiomem: Initialised: Registers at 0x3f200000
[ 3.420590] usbcore: registered new interface driver brcmfmac
[ 3.524613] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
[ 3.576141] brcmfmac: Firmware version = wl0: Aug 7 2017 00:46:29 version 7.45.41.46 (r666254 CY) FWID 01-f8a78378
[ 4.022466] systemd-journald[141]: Received request to flush runtime journal from PID 1
$ lsusb
Bus 001 Device 004: ID 04e2:1411 Exar Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ ls /dev
autofs kmsg null raw tty19 tty38 tty57 vcs
block log ppp rfkill tty2 tty39 tty58 vcs1
btrfs-control loop0 ptmx serial tty20 tty4 tty59 vcs2
bus loop1 pts serial1 tty21 tty40 tty6 vcs3
cachefiles loop2 ram0 shm tty22 tty41 tty60 vcs4
char loop3 ram1 snd tty23 tty42 tty61 vcs5
console loop4 ram10 stderr tty24 tty43 tty62 vcs6
cpu_dma_latency loop5 ram11 stdin tty25 tty44 tty63 vcsa
cuse loop6 ram12 stdout tty26 tty45 tty7 vcsa1
disk loop7 ram13 tty tty27 tty46 tty8 vcsa2
fb0 loop-control ram14 tty0 tty28 tty47 tty9 vcsa3
fd mapper ram15 tty1 tty29 tty48 ttyACM0 vcsa4
full mem ram2 tty10 tty3 tty49 ttyAMA0 vcsa5
fuse memory_bandwidth ram3 tty11 tty30 tty5 ttyprintk vcsa6
gpiochip0 mmcblk0 ram4 tty12 tty31 tty50 uhid vcsm
gpiochip1 mmcblk0p1 ram5 tty13 tty32 tty51 uinput vhci
gpiochip2 mmcblk0p2 ram6 tty14 tty33 tty52 urandom watchdog
gpiomem mqueue ram7 tty15 tty34 tty53 vc-cma watchdog0
hwrng net ram8 tty16 tty35 tty54 vchiq xconsole
initctl network_latency ram9 tty17 tty36 tty55 vcio zero
input network_throughput random tty18 tty37 tty56 vc-mem
$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
The PHP libaries are based on a document that was developed for the Modbus inside the BN and it works also for the A series what is more common. From modbus side and libaries it should work.
ReplyDeleteThanks Daniela you are exactly right. It's about a year since I looked at this code, and have just looked at the original toggio github - and it was actually developed for the BN - so no problem there.
DeleteBTW Did you look at the node-red sonoff stuff ?
Yes did try but no idea how this work with node red. I have no programming skills and i need instructions like yours...
Deletei also did try to run it with apache and did failure...because i have abs that need modules and nginx can not work with module rewrite for example and both on same computer is at far i know not possible.
Well I've taken the hint and begun to start to document my automation with node-red, it'll take a while though as I've lots to cover, and it's the case of where I should start - and both of my raspberry Pi's are in use full time atm - I use one as an octoprint 3D printer server and I've got a long queue of stuff to print - plus I've been having fun building my powerwall and adding a 7S BMS to it.
DeleteRe apache - if you give me something to troubleshoot I'll try as I use Apache much more than I do nginx, and actually wrote it on this PC which has Apache installed on it for development.
Ok i was thinking about this.. to make it easy and also to be compatible i suggest you look there http://www.solarpoweredhome.co.uk/ in the links are the libaries and documents
DeleteBut finaly to jump to this project...
http://diytechandrepairs.nu/raspberry-solar/
Loock the video and Mosst will be happy that there is a complete Raspberian solution with all the things that it needs preinstalled. In short time comes the V7 out.... The advantage of Grafana and Influxdb is that you go very flexible. Also the EMONPCMS is preinstalled there.
For yours Powerwall you have also a preconfigured Base and also a good forum with in my mind the best knowledge and help for the powerwalls. Daniel is also admin there. In that the ways are realy short.. and discussion is not so much heavy arround...
I hope my Sun GTIL will be integrated to and than i have all on same plattform....
But i guess for you as an advanced its also interesting with the powerwall discussion arround.
I gave you for extra the first ling because he is using the PyModbus libary and that is the base arround any scripts that have been done on PHP libaries.
Hi Daniela
DeleteI'd already come across the first one - they're doing something very similar in size and scale to me.
I'd also come across the second link's youtube channel, but not the RPi image that you're linking to - that's a really good resource.
While I think the Grafana stuff looks cool, it's not actually the way I'm headed. The dashboard I wrote is what I use for longer term monitoring of my system, but I often use an old phone which I have permanently set to look at a node-red dashboard, and use a tablet to turn things on and off as required.
I'd not come across EMONPCMS before, that looks interesting too.
As for powerwalls - I've gone down the Paul Kennett small packs method, which is working well for me atm.
I don't want to waste my time reinventing the wheel, and as you've pointed out there are lots of good resources out there - I think I'll be concentrating on documenting what I've done with node-red in the next few posts (first one detailing my setup now available http://randomsporadicprojects.blogspot.co.uk/2017/10/my-small-solar-power-system.html).
A.
Hi Andrew,
ReplyDeleteI just wanted to thank you for an excellent project and I now have the panels on my narrowboat logging merrily away to the pi. There are a couple of things that might be useful for other potential users. The USB RS485 converter would only work with the white trace green and white trace blue wires connected. The handbook for the BN controller is the same as the A series regarding the network cable connections but the blue/green, blue/trace blue and green/trace green combinations didn't work for me. I added a line to the crontab file that would give the right permissions to ttyUSB0 in the event that the pi had to restart (always a possibility on a boat!).
I only live on board for half of the year so I set up remote access using remot3.it and now I can monitor performance remotely using the on board mobile broadband connection. My next task is to write the data to an internet database which will mean that I can view the solar info on a web page rather than by logging in through the remot3.it service. I have another pi onboard which runs OpenHab and monitors temperature sensors that I have built with ESP8266 modules using MQTT. I hope to use Node Red to generate MQTT messages which will add to the OpenHab setup. I have looked at your Node Red code but I am seeing an error in debug mode which says:
function : (error)
TypeError: Object 12.95 has no method 'toFixed'
I haven't really done anything with Node Red before so I have no idea what the error is but I'll look into it.
So once again, thanks for producing an interesting and invaluable project. It was a bit of a challenge for me with the installation being remote but I overcame that problem. Ultimately I hope to have the information visible on the internet for when I am not on board and feeding into my OpenHab installation for when I am there.
Best Regards
George
Hi George nice to see also someone with a boat (you are in England, arn't you?) using the solution. I am common with Andrew its not the end. I did a demo some time for Internet but i am going now to transfer it to grafana and influx database. Did you try openplotter? i try with time to integrate it the solar. At the moment we go to build variations and i guess and hope andrew brings out a tutorial with apache..
DeleteWhich way you go with yours boat ? do you cross the channel... I am sitting in the netherlands and i plan 3000 km to go to the black see. Maybee we go together next year?
Hi George
DeleteGood stuff :)
The pinout for my A (from the manual is)
1 +5v
2 +5v
3 RS 485 B
4 RS 485 B
5 RS 485 A
6 RS 485 A
7 Ground
8 Ground
Not sure about colours, but it is a non-standard cable layout - I followed the instructions linked in my description.
Good idea re- crontab
Not come across remote.it before, but you could easily write to a different database, you'd have to configure your new database server to accept a user, probably from any IP, but could be more secure if needed, then just change the database credentials you have in the script for the new ones. I've another post on getting a system to do daily emails of status that may be sufficient for you.
I've got an openvpn server running on a pi zero W so that I can connect to my home and access my lan - that works a treat with a permanent connection, though I'm not sure how much connectivity you've got.
Sounds a nice setup, I'm currently reflashing a dozen IoT devices to be immune from the Krack attack (all respond/issue MQTT)
I've not played with openhab as node-red does everything I can think of that I need - re my flow
The 'toFixed' is a javascript function to round a number to a fixed number of decimal places - either Object 12.95 is of the wrong type, or perhaps is empty - that shouldn't be a dealbreaker - just remove the .toFixed(2) from the code where it appears and you'll get (or should do) an unrounded number.
Sounds like you've been busy, and you've got something that works and is useful - I should be posting some node-red stuff soon, so keep an eye out.
Andrew
I've just read your error message again.
Deletethe 12.95 will be your voltage
I think you may have modified the code a little so that either the .toFixed is being attempted on the whole object (probably msg) not on the 'Battery Voltage' variable within it in the payload.
My current 'parse data' has changed a fair bit from the posted code above but perhaps picking your way through the code below may help??
Keep in mind I've 2 controllers and some lipos, so this will not all apply but perhaps will help.
var voltage = msg.payload[0]['Battery Voltage'].toFixed(2);
var power = msg.payload[0]['Battery Charging power'].toFixed(2);
var loadpower = msg.payload[0]['Load power'].toFixed(2);
var net = (power - loadpower).toFixed(2);
var voltageandpower = voltage + ',' + power;
var lipovoltage = msg.payload[0]['Lipo voltage'];
if (msg.payload[0].HAStatus == 0){
var HAStatus = "Not Charging";
}
if (msg.payload[0].HAStatus == 1){
var HAStatus = "Float";
}
if (msg.payload[0].HAStatus == 2){
var HAStatus = "Boost";
}
if (msg.payload[0].HAStatus == 3){
var HAStatus = "Equalization";
}
if (msg.payload[0].HBStatus == 0){
var HBStatus = "Not Charging";
}
if (msg.payload[0].HBStatus == 1){
var HBStatus = "Float";
}
if (msg.payload[0].HBStatus == 2){
var HBStatus = "Boost";
}
if (msg.payload[0].HBStatus == 3){
var HBStatus = "Equalization";
}
if ((msg.payload.indexOf('Database') === -1) && msg.topic.indexOf('Database') === -1){
msg.topic = "Voltage";
msg.payload = voltage;
var msg1 = {topic:"Net Charging Power", payload: net};
var msg2 = {topic:"Load Power", payload: loadpower};
var msg3 = {topic:"Voltage", payload: voltage};
var msg4 = {topic:"HA Status", payload: HAStatus};
var msg5 = {topic:"HB Status", payload: HBStatus};
var msg6 = {topic:"Voltage and Charging Power", payload: voltageandpower};
var msg7 = {topic:"Lipo voltage", payload: lipovoltage};
return [msg, msg1, [msg1,msg2,msg3],msg3,msg4,msg5,msg6,msg7];
} else {
return;
}
Andrew
Hi andrew can you describe yours flash process there for the ESP8266 - 1? I did ask there if its fixed but they told me i have to compile the ESP and so i ask about yours method?
ReplyDeleteAllways a step by step procedure is prefered :-)
@Narrowboat Caxton i have done for Openplotter a limited Documentation. I strictly blog in German but i let run 5 translation engins that there is the documentation translated to 117 languages.. so sorry that the english is a bit ... well how should i say :-)...
ReplyDeleteOpenplotter is using signal k a Marineformat server that is using and transfering also NMEA0183 and NMEA2000 and additional Canboat that is working out the secret codes of the closed NMEA2000. I am looking to make the solution here for solar to include. If you give it a try and have success tell me please. In the meantime i try with DIYpowerwalls to include grafana and influxdb. In general exists also a script for installation special for the ESP8266 a raspberry installation script that is maintained and let you easy install all MQTT and node red requirements. This save you hours and days of painfull instalation. Openplotter do use it also but Maintainer did not make full instalation... I will communicate my findings soon. You find my blog at http://donau-grundel-schiff.de
Hi Andrew, I finally got it all together and set up a little website to display the stats online. Could you take a few minutes to review it and let me know if there are any errors or if you think that details need clarifying please? The address is http://solar.narrowboat.us . You can contact me by leaving a comment on my boating blog at www.narrowboat.us
ReplyDeleteMany Thanks
George
I'm trying to include "Generated Today" and "Max Battery voltage" into the example_web.php
ReplyDeleteDoes anyone know how to?
Hi Jaudao
DeleteThat data is in the stats data so...
begin php
require_once 'PhpEpsolarTracer.php';
$tracer = new PhpEpsolarTracer('/dev/ttyUSB21');
//change the /dev/ttyUSBxx to what yours is
if ($tracer->getStatData()) {
print "\nStatistical Data\n";
print "----------------------------------\n";
for ($i = 0; $i < count($tracer->statData); $i++){
print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->statKey[$i].": ".$tracer->statData[$i].$tracer->statSym[$i]."\n";
}
print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->statKey[2];
print str_pad($i, 2, '0', STR_PAD_LEFT)." ".$tracer->statKey[8];
} else {
print "Cannot get Statistical Data\n";
}
end php
Should pull the stats data, and then loop through all the values, and I think position 2 and 8 are the values you want but adjust as required
Not tested this so there may be a typo in there, this could then be incorporated into any web page.
Stats seems to be hit or miss,sometimes returning, sometimes not, this seems to be voltage related, so best results will be during daylight hours.
HTH
A.
Thank you, that worked!
DeleteColin! great work I was able to get the Exar drivers to work with my tracer USB cable. for the record your instructions also work on the Tracer CN series of MPPT controllers. Question though, how do you get your scripts to monitor a second MPPT controller?
ReplyDeleteThis comment has been removed by the author.
DeleteHi Pierre
DeleteAndrew here (Colin made the ESP8266 hardware that I use, and did post in this thread re my dashboard).
I run 2 controllers (with 2 home made wifi modules) so when I wrote the code I planned ahead.
In getsolarstats.php, modify the $solararray definition to include information about all your devices.
I assume you have 2 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';
I actually only use the $key part of the array, and the port and ip are unused (in this project).
That will change the program, and it will store the data in the database for you.
You will also have to modify the dashboard index.php to display the data from the second graph, duplicating some sections.
Thanks, what about the variable that defines the controller number ($i) seems to be set to a fixed value of 1 how does the loop change this value to define the controller number?
DeleteThere's a line
Delete//station id
$i++;
which increments the station id for each key in the loop, so you'll have data stored as controller 1 and controller 2
You can then change your queries to aggregate controller values as required eg amps voltage and watts, but produce separate graphs for each controller by itself.
Question on setting up updating of the "dials" In the original code the dials only query once when the page loads using
ReplyDelete-> "value": "realtimeData[4]
Can they be changed to auto updating dials using the following code
->
"dataStreamUrl": "http://localhost/epsolar/getsolarstats.php",
"refreshInterval": "10",
but how do you determine what value you are updating?
The dials get their data from a separate request for live data when the page loads, and the graphs get data from the database, which is populated by getsolarstats running periodically (every minute for me) - basically this makes a request for live data every minute and stores it.
ReplyDeleteThe original software has a minimum polling interval of 10s, so I'm guessing it will not work if a value lower than that is tried. As you increase this polling frequency, it also means that other requests for data are more likely to clash and you'll get a request that gets no data back - ie if you have a page with frequently updating figures your data logging feature may end up having gaps in the data it can retrieve.
I'm happy with 1min polling - but if you want more frequent updates, it is relatively simple to have a page eg livedata.php which your gauges use as a data source - that php page would request live data from the charge controller, get the data, parse it and return it to your chart in a format for direct update.
See https://www.fusioncharts.com/dev/chart-guide/standard-charts/real-time-charts for some inspiration.
There's also the possibility you could edit the page to to just show the dials and not the graphs, and simply put a metarefresh on the page to cause the whole page to refresh say every 15s simply pulling live data on each refresh.
HTH
Hello, i'm alos want to monitor my Epsolar Tracer, with TTL-RS485 adapter, can i doit with your tutorial? have a lot of erros: getsolarstats.php not returning any data, i use wire to my controller
ReplyDeletei have changed these:
$solararray["/dev/serial0"]["ip"] = '';;
$solararray["/dev/serial0"]["port"] = '';
but no signal, how can i test if the RS485 is working and on what port and baud rate?
/var/www/html/epsolar# ./getsolarstats.php
Hi Marsotica
ReplyDeleteThis solution does work with either the wired connector above, or the home made wifi one.
The only problem I've seen is that some wires can be recognised by your kernel as being a modem, and hence the wrong driver it used. Though in the cases I've heard about it doesnt mount as /dev/serial
I've posted the following for George above
--------
A bit of googling got me here https://github.com/kasbert/epsolar-tracer
This looks to contain a driver that you can use that will mount your device so that it's handled like a usb device, and will appear as ttyxRUSB0
device which may work with the software as you've tried to do ie replace ttyUSB0 with ttyxRUSB0 throughout. Note you have to compile the new kernel module, and disable the acm one for this to work.
The link above then manages to connect with a python script. As the page seems to be for Tracer A and BN, it make me thing the modbus may be the same, and therefore, this dashboard, and the phplibrary it uses may work.
I think this should get you connected from a pi, either with my dashboard, or at the very least with a pythons script.
----------
Pierre above got this to work on a RPi and left the following instructions
If you still have the other tracer USB cable, I got mine running using the github drivers. The problem with github is they assume that you already have the kernel headers installed which the Pi doesn't by default. you need to install the headers using sudo apt-get install raspberrypi-kernel-headers, then run the make and insmod commands. I also copied the resuolting *.ko file into the modules folder and added an endtry into the modules file. You'll also need to blacklist the ACM driver to keep it from installing.
-------------
If you did these things I think you'd be able to get it to mount as /dev/ttyUSB?? and then the change the array keys and you should connect.
Hope that helps
I only have a ttl to rs485, the usb adapter is not working, have another errors
Deletewhen i'm running the command it retuns this error: serial0 i'm using
/var/www/html/epsolar $ php example_cli.php
Timeout on reading from serial port
someone is able to get it work with windows wamp?
ReplyDeleteatleast read data from tracer A
This should work with WAMP but you'd need an alternative to socat - there are buy and free options to do this - see https://www.youtube.com/watch?v=dKZ35Enao4M for more information
Deleteevery times i try, i get : unable to set parity, unable to set baudrate etc.... no working at all (win10 64bit + usb cable that work with epsolar software)
ReplyDeleteI have this issue now and then, when I run the command "sudo socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:11.11.11.254:8088&"
ReplyDeleteand then run this command
"sudo chmod 777 /dev/ttyUSB21"
I get this output "chmod: cannot operate on dangling symlink â/dev/ttyUSB21â
[1]+ Done sudo socat pty,link=/dev/ttyUSB21,unlink-close=0,raw,echo=0 tcp:11.11.11.254:8088"
What does this mean, what can I do to fix this?
Hello
ReplyDeletegreat work thank you very much for the tutorial
I have the Epsolar IT4415ND connected by the original usb cable all works perfectly just not able to clean the battery SOC it returns it constantly value 2500
did anyone solve you the same problem?
thank you for the info
RealTime Data
----------------------------------
00 PV array voltage: 98.58V
01 PV array current: 6.16A
02 PV array power: 607.35W
03 Battery voltage: 57.46V
04 Battery charging current: 10.57A
05 Battery charging power: 607.35W
06 Load voltage: 57.46V
07 Load current: 0A
08 Load power: 0W
09 Battery temperature: 26.51°C
10 Charger temperature: 36.97°C
11 Heat sink temperature: 25°C
12 Battery SOC: 2500%
13 Remote battery temperature: 48°C
14 System rated voltage: 57.46V
15 Battery status: 0
16 Equipment status: 9
Hi Andrew,
ReplyDeletePerhaps you or other users can help me with the load setting on the epever. I continued to develop the node red dashboard and included a switch for the load based on your php code. It works as well as the button on the MT50 display but only when certain conditions are met. I have graphed the load voltage against the battery voltage and the pv voltage and have found the following.
If I leave the load switched on permanently, it will switch itself off when the battery voltage drops below 13.1v and will switch itself back on when the battery reaches 14.2v. There is no correlation with the PV voltage or whether it is day or night.
If the load is off and the battery voltage is below 14.1v and I switch the load on, nothing happens. Without further intervention, once the battery voltage reaches 14.1v, the load will automatically switch on so the system remembers that it had the signal. It’s a mystery to me so any help would be appreciated.
As a note to David (above). I don’t know why the SOC is displaying 2500% but don’t waste time trying to get to the bottom of it as the true reading will be meaningless anyway. The epever SOC is calculated from the battery voltage and the temperature. So in the first instance, you need the battery sensor connected. Even then the reading is meaningless unless there is no load on the batteries and they have been charged and equalised. I have a shunt on my battery bank which amongst other things, counts amps in and out of the battery bank. This is the most accurate way of determining the SOC.
Best Regards
George
This comment has been removed by the author.
ReplyDeleteHi Andrew, thank you for the guide. I have had this up and running for a few months now, but I have just noticed something very strange. If I switch the load off when the Raspberry Pi is connected to the COM port on the Tracer, the load does not switch off, instead the voltage output on the load drops from say the battery charge 12.7V to 12V or thereabouts and therefore anything I have connected to the load stays powered on. If I remove the RJ45 cable from the Tracer or the USB RS485 adapter from the Pi and then switch the load off, it works fine. e.g. the load voltage drops to zero.
ReplyDeleteI followed Adam Welchs video on Youtube ref the Green and Blue wire, today I changed the wiring to the RS485 to the two blue wires in the RJ45 lead that I saw at http://www.solarpoweredhome.co.uk/
But I have exactly the same issue, are you seeing this issue at all or have any idea how to solve it. It is pretty annoying as I cannot dump the load if the Pi is connected and if I disconnect the Pi I cannot look at the charts or remotely switch the load on or off (not that it currently switches the load off that is). I only recently needed the ability to remotely switch the load on/off and hence the reason I have only just noticed this problem.
I wanted to come by and say thank you for your fantastic work!
ReplyDeleteYour work was the genesis of my current setup. Using Node Red on the raspberry pi, I am reading, via MODBUS, all the registers in real-time. I opted this model as it gives me fast data and i didn't really need the database.
Setup:
Tracer 4210AN ---> usb to RS485 ---> Raspberry Pi ---> Node Red ---> MODBUS
I am still working on the setup, for example I want to be able to write directly to the load registers so that i can manually turn it on/off.
Thank you again!
Hi. Great software, and I have this running on one Raspberry Pi with no problems. But I have just done a second installation using another Raspberry but with a different model controller (info.py shows it as Tracer2215BN). So the info.py works fine, as does the windows EPEver software but running index.php from this package gives message "Timeout on reading from serial port". Driver is loaded OK and shows as /dev/ttyXRUSB0.
ReplyDeleteAny Ideas?
Cheers Andi
Hi, I'm new to arduino - I have NodeMCU D1 Mini (in the arduino interface I've selected NodeMCU 1.0 (ESP 12-E Module)) in the IDE. I made the change to the 3100 section as detailed in the top of your post but I'm getting nothing at all.
ReplyDeleteI've got it wired to the Mini as follows - white/blue to TX, green to RX, blue to Ground. Tried swapping TX/Rx around but nowt.
(pins 5 - blue/white,6 green and 7 blue)
Any thoughts - or did you wire your D1 differently.
I have a 30A MPPT EP Solar Tracer. I also have the MT5.
Hi,
ReplyDeleteplease help me out here...
pi@raspberrypi:~/epeverlogger $ sudo chmod 777 /dev/ttyUSB21
chmod: cannot operate on dangling symlink '/dev/ttyUSB21'
This is the second time I have set this up, the first time I followed this guide 100% on a Raspberry Pi 2 and it worked flawlessly. This second time I set it up on a Pi Zero and deviated from using Nginx to Apache, but I have a very slight issue on the Pi Zero in that the Fusioncharts do not show the No. below them, well the Nett Current (A) does, but the rest of the stats do not!. The dials all work and point to where they should and the performance history also works fine.
ReplyDeleteAnyone any ideas?, maybe something has changed in the latest Fusioncharts. If no one has an idea, perhaps you could post a link to a copy of Fusioncharts that works for you, so I can rule out a newer version being the problem? - I wiped my Pi 2 a few weeks ago, so lost all the files that was on it, so I don't have that version of Fusioncharts (that's assuming that is the issue).
What a huge waste of time that was!, I "figured out" this only happened with the .fint theme, I tried all the other themes and the valuebelowpivot is shown fine, but I didn't like the layout of the other themes. I eventually found the fusioncharts.zip I downloaded last year, replaced the newer version with this older version but the result was the same. I disabled Ublock on Chromium = same result. I installed Firefox-ESR = Same result. I then installed the Midori browser and the Pivotvalue shows fine under all gauges. I used Midori on my Pi2 on my previous install of this, so this issue never cropped up then!. Not sure how to fix this - but something about Chromium and Firefox-ESR does not like dispalying the Pivot values when using the fint theme - oh well, I'm happy using Midori. If anyone else has this issue, you can try the above :-)
ReplyDeleteGood morning.
ReplyDeleteFirst, congratulate him on this project.
My question would be the following:
I have the following loading charger: LS2024B
It also has Standard Modbus communication protocol with RS485 interface
Thank you
Good morning.
ReplyDeleteFirst, congratulate him on this project.
My question would be the following:
I have the following loading charger: https://www.epsolarpv.com/product/10.html
It also has Standard Modbus communication protocol with RS485 interface
Functional without problems?
Thank you
after following this guide,getting lost and finding my way.I Would like to say thanks to Randomsporadicprojects for this guide and i want to contribute a bit so if any of you face the same issue will come on top.
ReplyDeleteI took all the steps from this guide, but after tinkering a lot i come to the conclusion:
You need PHP, MYSQL
Always remember to change access and run permissions on any file you make.
Download the GitHub connection files from https://github.com/toggio/PhpEpsolarTracer
If you are using the usb to rj45 cable that came with the controller please download the drivers https://github.com/kasbert/epsolar-tracer/tree/master/xr_usb_serial_common-1a
I made a simple scrip to run at boot time to delete the driver that Linux uses and re install this one " i know there is a better way, but is just simpler"
########################################
#!/bin/bash
##To remove the CDC-ACM driver and install the driver:
sudo rmmod cdc-acm
sudo modprobe -r usbserial
sudo modprobe usbserial
sudo insmod /var/www/html/epsolar/drivers/epsolar-tracer/xr_usb_serial_common-1a/xr_usb_serial_common.ko
#####################################
Using the modify version of the connector (getsolarstats.php) i just replace ttyUSB21 with the one that my pi told me it had(ttyXRUSB0")
Deletei also added more stuff i wanted to capture, here is my version:
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`,`Battery SOC`,`Battery temperature`,`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[12]);
$sth->BindParam(10, $tracer->realtimeData[9]);
$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++;
}
}
duplicate getsolarstats.php and rename it however you want i named mine accstats.php
Deletejust add this part ( this is to capture the generated power)
while (list ($key, $val) = each($solararray)) {
$tracer = new PhpEpsolarTracer($key);
if ($tracer->getStatData()) {
$sth = $dbh->prepare("insert into accstats (`Controller`,`timestamp`,`Generated energy today`,`Generated energy this moth`,`Generated energy this year`,`Total generated energy`) values (?,?,?,?,?,?)");
$sth->BindParam(1, $i);
$sth->BindParam(2, $time);
$sth->BindParam(3, $tracer->statData[8]);
$sth->BindParam(4, $tracer->statData[9]);
$sth->BindParam(5, $tracer->statData[10]);
$sth->BindParam(6, $tracer->statData[11]);
$sth->execute();
//station id
$i++;
}
}
hose where my mayor deviations.
ReplyDeletehere its my Node red dash with all the info.
Note: you must add a second query and second table
SELECT `Battery voltage`,`Battery charging power`,`Battery charging current`,`PV array voltage`,`PV array current`,`PV array power`,`Battery temperature`,`Battery SOC` FROM stats ORDER BY `timestamp` DESC LIMIT 1;
SELECT `Generated energy today`,`Generated energy this moth`,`Generated energy this year` FROM accstats ORDER BY `timestamp` DESC LIMIT 1;
Mi node red config is bug and cant be posted here. :(
Deleteits big**. char limit on here.
DeleteCan someone post a link to fusioncharts.zip... may be your copy.
ReplyDeleteI can't find it on http://www.fusioncharts.com/
Hi Donald
DeleteApologies for not replying sooner, I don't monitor this blog that often.
Things have moved on since I wrote this article.
A 14 day trial of fusioncharts can be downloaded from https://www.fusioncharts.com/download/fusioncharts-suite-xt but I don't think it expires.
That said, I now use a wemos d1 mini connected to the RS485 board and modified cable as mentioned above, and send that via wifi to an MQTT topic. I then save that message using node-red and mysql, and then graph the output in node-red using the dashboard node. This could be changed to using influxdb and grafana if you'd prefer.
I've been using the wemos for 2-3 years now and it works without issue.
HTH
For anyone following i've created a new board that i launched earlier this year that can post the data straight to a MQTT broker or an influxdb directly https://store.eplop.co.uk/product/epever-rs485-to-wifi-adaptor-new-revision/
ReplyDeleteEpever mppt solar charge controller I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much.
ReplyDeletecustom solar panels I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much.
ReplyDeleteTo Learn More About The Top MT5 White Label Solution, visit MT5 White Label Solution
ReplyDelete