Victron MPPT data using Arduino serial
Reading Victron MPPT Data
References
Parts Required
- Victron BlueSolar MPPT 75/15 Retail SCC010015050R - $135 (Note that this unit is not Bluetooth enabled) [1]
- JST Jumper 4 Wire Assembly - $2.75 [2]
- Arduino Uno
Victron Label descriptions for MPPT Solar Panel Charge Controller
- This extract is taken from page 6 of the VE.Direct Protocol.
- V - battery voltage measured in milliVolts (mV)
- VPV - Solar panel voltage (mV)
- PPV - Power output from the Solar Panel (Watts). Note that if the battery is fully charged the MPPT will set power to zero to prevent the battery over charging.
- I - current from the MPPT charge controller to the battery (mA). This will also be zero if the battery if fully charged.
- LOAD - not being used.
- The VE.Direct Protocol document page 7.
- No significant labels for the MPPT.
- The VE.Direct Protocol document page 8.
- H19 - Total yield from the MPPT controller in kiloWatt hours (0.01 kWh). Note that this is the actual kWh multiplied by 100. To obtain the true kWh divide the result by 100.
- H20 - Yield today (0.01 kWh).
- H21 - Maximum power today (W).
- H22 - Yield yesterday (0.01 kWh). Remember to divide this result by 100 to get the true value.
- H23 - Maximum power yesterday (W)
- ERR - Error codes. Normally 0 when operating correctly.
- CS - Charge state of battery (3-Bulk, 4-Absorption and 5-Float modes).
- PID - Product ID - useful for identifying which Victron unit is connected to which USB port.
- SER - Serial number
- And here is the output from the Victron MPPT Charge Controller using the command vedirect --port=/dev/ttyUSB0
- Note that the USB port will be different from different devices and may change if more than one USB device is connected.
Voltage considerations for different Victron hardware
- Victron MPPT operates at 5V.
- Arduino Uno also operates at 5V so no digital converter required.
VE.Direct Pinout
Serial Port Configuration - VE.Direct
Fritzing Circuit Diagram
Photos of Circuit
Arduino Code - Image
Serial Monitor - Example Output
Arduino Code - Code
/* Connections:
MPPT pin MPPT Arduino Arduino pin
1 GND GND GND
2 RX TX - do not use!
3 TX RX 7 (UNO)
4 Power+ none - do not use!
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
void setup()
{
Serial.begin(9600);
mySerial.begin(19200);
}
void loop()
{
if (mySerial.available())
{
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
Serial.println(label + val);
}
}
Arduino Code - Code - Reading Battery Voltage - V
/* Connections:
MPPT pin MPPT Arduino Arduino pin
1 GND GND GND
2 RX TX - do not use!
3 TX RX 7 (UNO)
4 Power+ none - do not use!
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
void setup()
{
Serial.begin(9600);
mySerial.begin(19200); // baud rate for MPPT
}
void loop()
{
if (mySerial.available())
{
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
if (label == "V"){
Serial.println(label + val);
}
}
}
Arduino Code - Code - Reading other Parameters from MPPT
/* Connections:
MPPT pin MPPT Arduino Arduino pin
1 GND GND GND
2 RX TX - do not use!
3 TX RX 7 (UNO)
4 Power+ none - do not use!
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
void setup()
{
Serial.begin(9600);
mySerial.begin(19200); // baud rate for MPPT
}
void loop()
{
if (mySerial.available())
{
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
if (label == "V"){
Serial.println(label + val); // Battery Voltage
}
if (label == "VPV"){
Serial.println(label + val); // Solar Panel Voltage
}
if (label == "PPV"){
Serial.println(label + val); // Solar Panel Power (Watts)
}
}
}
XBee Test - with MPPT
- Noticed that as soon as Software Serial added for MPPT communication is only one way from Arduino MPPT to XBee receiver for Pi.
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
//XBee.write(mySerial.read());
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
XBee.write(55); // DEC 55 = HEX #37
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
XBee - MPPT Test to send Battery Voltage data using XBee
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
char char_array[10]; // for data from MPPT to XBee
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
//XBee.write(mySerial.read());
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
//XBee.write(55); // DEC 55 = HEX #37
int str_len = val.length() + 1;
val.toCharArray(char_array, str_len);
XBee.write(char_array);
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
XBee XCTU Console output
XBee - MPPT Test to send All Data using XBee
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
String V_data = "0";
String VPV_data = "0";
String PPV_data = "0";
String IL_data = "0";
String ALL_data = "";
char ALL_char_array[25];
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
V_data = val;
}
if (label =="VPV"){
VPV_data = val;
}
if (label =="PPV"){
PPV_data = val;
}
if (label =="IL"){
IL_data = val;
}
if (label == "LOAD"){
ALL_data = V_data + "," + VPV_data + "," + PPV_data + "," + IL_data;
int str_len = ALL_data.length() + 1;
ALL_data.toCharArray(ALL_char_array, str_len);
XBee.write(ALL_char_array);
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
XBee - MPPT Test to send All Data using XBee with End of Line
- Data stored in Strings trimmed to remove white space
- New line character added to end of String so that Python can determine end of transmission
- During programming the XBee was plugged into Arduino.
- XBee Explorere shield switch permanently on DLine (not UART)
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
String V_data = "0";
String VPV_data = "0";
String PPV_data = "0";
String IL_data = "0";
String ALL_data = "";
char ALL_char_array[25];
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
//Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
V_data = val;
V_data.trim();
}
if (label =="VPV"){
VPV_data = val;
VPV_data.trim();
}
if (label =="PPV"){
PPV_data = val;
PPV_data.trim();
}
if (label =="IL"){
IL_data = val;
IL_data.trim();
}
if (label == "LOAD"){
ALL_data = V_data + "," + VPV_data + "," + PPV_data + "," + IL_data + "\n";
int str_len = ALL_data.length() + 1;
ALL_data.toCharArray(ALL_char_array, str_len);
XBee.write(ALL_char_array);
//Serial.println(ALL_data);
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
XBee - MPPT Test - Printing data to the Arduino IDE Serial Monitor
- Serial monitor uses pins 0 and 1
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
String V_data = "0";
String VPV_data = "0";
String PPV_data = "0";
String IL_data = "0";
String ALL_data = "";
char ALL_char_array[25];
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
V_data = val;
V_data.trim();
}
if (label =="VPV"){
VPV_data = val;
VPV_data.trim();
}
if (label =="PPV"){
PPV_data = val;
PPV_data.trim();
}
if (label =="IL"){
IL_data = val;
IL_data.trim();
}
if (label == "LOAD"){
ALL_data = V_data + "," + VPV_data + "," + PPV_data + "," + IL_data + "\n";
int str_len = ALL_data.length() + 1;
ALL_data.toCharArray(ALL_char_array, str_len);
XBee.write(ALL_char_array);
Serial.println(ALL_data);
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
Plot Data
import pandas as pd
import plotly.express as px
# Step 1: Import the necessary libraries
# Step 2: Read the data from the text file into a Pandas DataFrame
data = pd.read_csv('/home/pi/Tiny_House_8/tiny_house_8_data.txt')
# Step 3: Create a Plotly figure with a scatter plot for 'intTemp' only
fig = px.scatter(data, x='datetime', y='intTemp',
labels={'datetime': 'Date and Time', 'intTemp': 'Internal Temperature (°C)'},
title='Internal Temperature')
# Step 4: Customize the plot layout
fig.update_layout(xaxis_title='Date and Time', yaxis_title='Temperature (°C)')
# Step 5: Save the plot as an HTML file
fig.write_html('/home/pi/Tiny_House_8/internal_temperature_plot_tiny_house_8.html')
print("Internal temperature plot saved as internal_temperature_plot.html file")
Put XBee to Sleep to Conserve Power
- The XBee will enter hibernation when the DTR pin (pin 9 on the XBee) is brought high (3.3 V).
- It will wake from hibernation when this pin is brought low (0 V).
- Here is the circuit required to achieve this. Note that Pin 9 on the Arduino and XBee are linked.
- Pin 9 (Arduino)
- |
- |
- |—-10 kOhm—-Vcc (3.3 V)
- |
- |
- Pin 9 DTR (XBee)
- The basic principles of operation are as follows.
- To put the XBee to sleep, the Arduino’s pin 9 is configured as an input and set high (3.3 V).
- Then the 10 kOhm pull-up resistor brings the voltage on the XBee’s pin 9 high also.
- To wake the XBee, the Arduino’s pin 9 is configured as an output and set low (0 V).
- The ATmega328 can not only source current, it can also sink up to about 40 mA of current which is more than enough to bring the voltage on the XBee’s pin 9 low and wake the XBee from hibernation.
- Below is an outline of the Arduino code I use. I’ve incorporated this code into a larger routine that uses the watchdog timer to put the ATmega328 to sleep too.
Set up without Pin Hibernation
Close up of Arduino Set-up WITH Pin Hibernation
Example Code for XBee Sleep
const int XBee_wake = 9; // Arduino pin used to sleep the XBee
void setup(void) {
// nothing special here
}
void loop(void) {
// wake up the XBee
pinMode(XBee_wake, OUTPUT);
digitalWrite(XBee_wake, LOW);
// do whatever I need to do with the XBee
// put the XBee to sleep
pinMode(XBee_wake, INPUT); // put pin in a high impedence state
digitalWrite(XBee_wake, HIGH);
}
Full XBee Code
- Extra variable count added to improve data integrity after sleep.
- Found that the one was occasionally being dropped from the 12 Volt data set.
- Looping 5 times after sleep seems to fix this.
- Also found out that the AT commands for the XBee don't work.
- The XBee can also be instructed to sleep using AT commands.
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
String V_data = "0";
String VPV_data = "0";
String PPV_data = "0";
String IL_data = "0";
String ALL_data = "";
const int XBee_wake = 9;
int count = 0;
char ALL_char_array[25];
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Battery current (mA)
// IL = Load Current (mA)
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from MPPT, send it out to XBee
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
if (label =="V"){
V_data = val;
V_data.trim();
}
if (label =="VPV"){
VPV_data = val;
VPV_data.trim();
}
if (label =="PPV"){
PPV_data = val;
PPV_data.trim();
}
if (label =="IL"){
IL_data = val;
IL_data.trim();
}
count += 1;
// collect MPPT data 5 times to prevent any misreads. One data read per second.
if (label == "LOAD" && count > 5){
ALL_data = V_data + "," + VPV_data + "," + PPV_data + "," + IL_data + "\n";
int str_len = ALL_data.length() + 1;
ALL_data.toCharArray(ALL_char_array, str_len);
XBee.write(ALL_char_array);
Serial.println(ALL_data);
//delay(60000); //1 minute
//put XBee to sleep
pinMode(XBee_wake, INPUT);
digitalWrite(XBee_wake, HIGH);
Serial.println("Asleep");
delay(300000);
// wake up XBEE
pinMode(XBee_wake, OUTPUT);
digitalWrite(XBee_wake, LOW);
Serial.println("Awake");
delay(1000);
count = 0;
}
}
if (XBee.available()) {
char response = XBee.read();
Serial.write(response);
Serial.println(response);
}
}
XBee - MPPT Test - Python code
#!/usr/bin/env python3
import serial
import time
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
print(count)
time.sleep(0.1)
try:
#line = ser.readline()
line = ser.readline().decode('utf-8').rstrip()
print(line)
except:
print("fail")
count += 1
XBee - MPPT - Separating incoming data into separate variables
- Incoming data separated into separate variable.
- V = Battery voltage (mV)
- VPV = Solar Panel voltage (mV)
- PPV = Solar panel power (W)
- IL = Load Current (mA)
#!/usr /bin/env python3
import serial
import time
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
try:
#line = ser.readline()
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
#count += 1
XBee - MPPT - Add Datetime Stamp
- Add DateTime stamp
- import datetime required.
#!/usr /bin/env python3
import serial
import time
import datetime
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
#count += 1
XBee - MPPT - Saving Data every Five Minutes
- Set the statement if count > 300 to save data every 5 minutes (300 seconds).
- For testing purposes the count can be set to 10.
count += 1
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
Full code - most recent - 24 Oct 2023
- This code listens for data transmissions from the XBee.
- The XBee will only send data once every 5 minutes.
- The XBee module sleeps between data transmissions to save energy.
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
count += 1
if count > 0:
# Save data
print("Saving data")
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT_Pb/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1-SMC?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
Full code - older version
- Older version of the code - works but relies on constant sending of data from XBee.
- Constant transmission of data from the XBee uses up more power.
#!/usr /bin/env python3
import serial
import time
import datetime
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
count += 1
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
XBee - MPPT - Dweet data
- import requests required to Dweet data
- Added datetime stamp to dweeted data
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
dweet_dict.update({"datetime": str(date_stamp)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
Full code
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
count += 1
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
dweet_dict.update({"datetime": str(date_stamp)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
XBee - MPPT - Plotting data
- New plotly method - to update
- The following imports are required to plot data
- import plotly
- import plotly.graph_objects as go
- import pandas
# import and plot data text file
df = pandas.read_csv('/home/pi/MPPT/MPPT_data.txt')
fig = go.Figure(data = go.Scatter(mode='markers',
x=df.date_time,
y=df.V,
marker=dict(
color="LightSkyBlue",
size=20)
)
)
fig.update_layout(title="Voltage of Solar MPPT Battery (mV)",
xaxis_title = 'Time',
yaxis_title = 'Battery voltage (mV)',
font=dict(
size=20,
color="RebeccaPurple"
)
)
plotly.offline.plot(fig,
filename="/home/pi/MPPT/MPPT_data_plot.html",
auto_open=False)
print("Battery Voltage data plotted")
Full code
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
import plotly
import plotly.graph_objects as go
import pandas
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
count += 1
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
# import and plot data text file
df = pandas.read_csv('/home/pi/MPPT/MPPT_data.txt')
fig = go.Figure(data = go.Scatter(mode='markers',
x=df.date_time,
y=df.V,
marker=dict(
color="LightSkyBlue",
size=20)
)
)
fig.update_layout(title="Voltage of Solar MPPT Battery (mV)",
xaxis_title = 'Time',
yaxis_title = 'Battery voltage (mV)',
font=dict(
size=20,
color="RebeccaPurple"
)
)
plotly.offline.plot(fig,
filename="/home/pi/MPPT/MPPT_data_plot.html",
auto_open=False)
print("Battery Voltage data plotted")
Full code - Updated 25 Oct 2023
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
count += 1
if count > 0:
# Save data
print("Saving data")
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT_Pb/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
dweet_dict.update({"datetime": str(date_stamp)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1-SMC?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
Full Code - Plot Battery (V) data - Updated 25 Oct 2023
import pandas as pd
import plotly.express as px
# Step 1: Import the necessary libraries
# Step 2: Read the data from the text file into a Pandas DataFrame
data = pd.read_csv('/home/pi/MPPT_Pb/MPPT_data.txt')
# Step 3: Create a Plotly figure with a scatter plot for 'intTemp' only
fig = px.scatter(data, x='datetime', y='V',
labels={'datetime': 'Date and Time', 'V': 'Battery Voltage'},
title='MPPT Battery Voltage')
# Step 4: Customize the plot layout
fig.update_layout(xaxis_title='Date and Time', yaxis_title='Battery Voltage')
# Step 5: Save the plot as an HTML file
fig.write_html('/home/pi/MPPT_Pb/MPPT_battery_voltage.html')
print("Battery voltage data plotted")
Full Code - Updated - Plot Solar Panel Voltage (VPV) - Updated 25 Oct 2023
import pandas as pd
import plotly.express as px
# Step 1: Import the necessary libraries
# Step 2: Read the data from the text file into a Pandas DataFrame
data = pd.read_csv('/home/pi/MPPT_Pb/MPPT_data.txt')
# Step 3: Create a Plotly figure with a scatter plot for 'intTemp' only
fig = px.scatter(data, x='datetime', y='VPV',
labels={'datetime': 'Date and Time', 'VPV': 'Solar Panel Voltage'},
title='MPPT VPV Solar Panel Voltage')
# Step 4: Customize the plot layout
fig.update_layout(xaxis_title='Date and Time', yaxis_title='Solar Panel Voltage')
# Step 5: Save the plot as an HTML file
fig.write_html('/home/pi/MPPT_Pb/MPPT_solar_panel_voltage.html')
print("Solar Panel voltage data plotted")
XBee - MPPT - Error Logs
- Noticed that solar data was missing in this plot.
- Not sure what the error was so decided to add an Error Log to help troubleshoot.
- An example of an error log is included below.
- The date_time stamp is recorded together with a simple text message.
- The information is saved in a text file named MPPT_error_log.txt
print("Read serial fail")
data = date_stamp + "," + "Read serial fail" + "\n"
f = open('/home/pi/MPPT/MPPT_error_log.txt','a')
f.write(data)
f.close()
Full code
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
import plotly
import plotly.graph_objects as go
import pandas
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
IL = mylist[3] ## Load Current (mA)
print(f'Battery voltage {V}, Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}, Load current {IL}')
except:
V = "0"
VPV = "0"
PPV = "0"
IL = "0"
print("Read serial fail")
data = date_stamp + "," + "Read serial fail" + "\n"
f = open('/home/pi/MPPT/MPPT_error_log.txt','a')
f.write(data)
f.close()
count += 1
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + IL + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"IL": str(IL)})
dweet_dict.update({"Time": str(date_stamp)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
data = date_stamp + "," + "Dweet fail" + "\n"
f = open('/home/pi/MPPT/MPPT_error_log.txt','a')
f.write(data)
f.close()
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
# import and plot data text file
df = pandas.read_csv('/home/pi/MPPT/MPPT_data.txt')
fig = go.Figure(data = go.Scatter(mode='markers',
x=df.date_time,
y=df.V,
marker=dict(
color="LightSkyBlue",
size=20)
)
)
fig.update_layout(title="Voltage of Solar MPPT Battery (mV)",
xaxis_title = 'Time',
yaxis_title = 'Battery voltage (mV)',
font=dict(
size=20,
color="RebeccaPurple"
)
)
plotly.offline.plot(fig,
filename="/home/pi/MPPT/MPPT_data_plot.html",
auto_open=False)
print("Battery Voltage data plotted")
XBee - MPPT - Freeboard IO
Add Data Source
Design Dashboard
Reading all Victron MPPT Charge Controller Data Values
/*****************************************************************
XBee_Serial_Passthrough.ino
Set up a software serial port to pass data between an XBee Shield
and the serial monitor.
Hardware Hookup:
The XBee Shield makes all of the connections you'll need
between Arduino and XBee. If you have the shield make
sure the SWITCH IS IN THE "DLINE" POSITION. That will connect
the XBee's DOUT and DIN pins to Arduino pins 2 and 3.
*****************************************************************/
// We'll use SoftwareSerial to communicate with the XBee:
#include <SoftwareSerial.h>
//For Atmega328P's
// XBee's DOUT (TX) is connected to pin 2 (Arduino's Software RX)
// XBee's DIN (RX) is connected to pin 3 (Arduino's Software TX)
SoftwareSerial XBee(2, 3); // RX, TX
SoftwareSerial mySerial(7, 8); // RX, TX
String label, val;
String V_data = "0";
String VPV_data = "0";
String PPV_data = "0";
String I_data = "0";
String IL_data = "0";
String LOAD_data = "0";
String H19_data = "0";
String H20_data = "0";
String H21_data = "0";
String H22_data = "0";
String H23_data = "0";
String ERR_data = "0";
String CS_data = "0";
String HSDS_data = "0";
String ALL_data = "";
char ALL_char_array[250];
// V = Battery voltage (mV)
// VPV = Solar Panel voltage (mV)
// PPV = Solar panel power (W)
// I = Main Battery current (mA)
// IL = Load Current (mA)
// LOAD = Load output state (ON/OFF)
// H19 = Yield total (0.01 kWh)
// H20 = Yield today (0.01 kWh)
// H21 = Maximum power today (W)
// H22 = Yield yesterday (0.01 kWh)
// H23 = Maximum power yesterday (W)
// ERR = Error code
// CS = State of operation (3-Bulk, 4-Absorption, 5-Float)
// HSDS = Day sequence number (0..364)
void setup()
{
// Set up both ports at 9600 baud. This value is most important
// for the XBee. Make sure the baud rate matches the config
// setting of your XBee.
XBee.begin(9600);
mySerial.begin(19200); // baud rate for MPPT is 19200
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{ // If data comes in from serial monitor, send it out to XBee
XBee.write(Serial.read());
}
if (mySerial.available())
{ // If data comes in from serial monitor, send it out to XBee
label = mySerial.readStringUntil('\t');
val = mySerial.readStringUntil('\r\r\n');
// V = Battery voltage (mV)
if (label =="V"){
V_data = val;
V_data.trim();
}
// VPV = Solar Panel voltage (mV)
else if (label =="VPV"){
VPV_data = val;
VPV_data.trim();
}
// PPV = Solar panel power (W)
else if (label =="PPV"){
PPV_data = val;
PPV_data.trim();
}
// I = Main Battery current (mA)
else if (label =="I"){
I_data = val;
I_data.trim();
}
// IL = Load Current (mA)
else if (label =="IL"){
IL_data = val;
IL_data.trim();
}
// LOAD = Load output state (ON/OFF)
else if (label =="LOAD"){
LOAD_data = val;
LOAD_data.trim();
}
// H19 = Yield total (0.01 kWh)
else if (label =="H19"){
H19_data = val;
H19_data.trim();
}
// H20 = Yield today (0.01 kWh)
else if (label =="H20"){
H20_data = val;
H20_data.trim();
}
// H21 = Maximum power today (W)
else if (label =="H21"){
H21_data = val;
H21_data.trim();
}
// H22 = Yield yesterday (0.01 kWh)
else if (label =="H22"){
H22_data = val;
H22_data.trim();
}
// H23 = Maximum power yesterday (W)
else if (label =="H23"){
H23_data = val;
H23_data.trim();
}
// ERR = Error code
else if (label =="ERR"){
ERR_data = val;
ERR_data.trim();
}
// CS = State of operation (3-Bulk, 4-Absorption, 5-Float)
else if (label =="CS"){
CS_data = val;
CS_data.trim();
}
else if (label == "HSDS"){
HSDS_data = val;
HSDS_data.trim();
ALL_data = V_data + "," +
VPV_data + "," +
PPV_data + "," +
I_data + "," +
IL_data + "," +
LOAD_data + "," +
H19_data + "," +
H20_data + "," +
H21_data + "," +
H22_data + "," +
H23_data + "," +
ERR_data + "," +
CS_data + "," +
HSDS_data + "\n";
int str_len = ALL_data.length() + 1;
ALL_data.toCharArray(ALL_char_array, str_len);
XBee.write(ALL_char_array);
Serial.println(ALL_data);
}
}
if (XBee.available())
{ // If data comes in from XBee, send it out to serial monitor
Serial.write(XBee.read());
}
}
Sending Weather Data to Arduino
- Data, such as weather data, can be uploaded from a Raspberry Pi to an Arduino via XBee.
- This allows finer control or heating or cooling cycles.
- For example if a series of hot days is predicted, then heating can be minimised.
- Example Communication Test
State of Charge Calibration for Victron 12V 8Ah Deep Cycle AGM Battery
- Battery was fully charged using Swallow Battery Charger.
- The battery is fully charged when the battery voltage is 14.00V and the charge current drops to 0.23A.
- The aim of the experiment is to apply a constant load (approximately 70mA - using the Arduino and the MPPT as loads) and monitoring the voltage drop on the battery with time.
- The battery voltage readings will be transmitted using XBee and stored on a Raspberry Pi.
- A 12V battery rated at 8Ah has a theoretical capacity of 96 Ah (12V x 8Ah).
- A 70mAh (0.07Ah) load should last for approx 114 Hours (8Ah / 0.07Ah)
- However, with we only deplete the battery to 75% of the full capacity - the battery should be able to support this fixed load for 28.5 hours (114 hours / 4).
- So for this experiment we will drain the battery for 28.4 hours using this set load and then note the final voltage.
- This final voltage will become our reading for 75% SOC (State of Charge).
- To maintain good battery health and longevity it will be important to stay above this battery voltage reading (SOC).
- Note that this battery voltage reading is only relevant for the 70mA load. A greater load will cause the battery voltage to drop lower.
Hardware Configuration
Python code on Raspberry Pi to monitor Battery Voltage
- In this example the Python code on the Raspberry Pi will be modified to read all Victron MPPT Charge Controller Data Values as provided by the Arduino code above.
#!/usr /bin/env python3
import serial
import time
import datetime
import requests
import plotly
import plotly.graph_objects as go
import pandas
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.reset_input_buffer()
count = 0
while True:
if ser.in_waiting > 0:
#print(count)
time.sleep(0.1)
print()
now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f'The current date and time is {date_stamp}')
try:
line = ser.readline().decode('utf-8').rstrip()
print(f"Data separated using commas {line.split(',')}")
mylist = line.split(',')
#print(f'My List {mylist}')
V = mylist[0] ## Battery Voltage (nV)
VPV = mylist[1] ## Solar Panel Voltage (mV)
PPV = mylist[2] ## Solar Panel Power (W)
I = mylist[3] ## Main Battery Current (mA)
IL = mylist[4] ## Load Current (mA)
LOAD = mylist[5] ## Load output state (ON/OFF)
H19 = mylist[6] ## H19 = Yield total (0.01 kWh)
H20 = mylist[7] ## H20 = Yield today (0.01 kWh)
H21 = mylist[8] ## H21 = Maximum power today (W)
H22 = mylist[9] ## H22 = Yield yesterday (0.01 kWh)
H23 = mylist[10] ## H23 = Maximum power yesterday (W)
ERR = mylist[11] ## ERR = Error code
CS = mylist[12] ## CS = State of operation (3-Bulk, 4-Absorption, 5-Float)
HSDS = mylist[13] ## HSDS = Day sequence number (0..364)
print(f'Battery voltage {V}')
print(f'Solar Panel voltage {VPV}')
print(f'Solar Panel power {PPV}')
print(f'Main battery current {I}')
print(f'Load current {IL}')
print(f'Load output state {LOAD}')
print(f'H19 Yield total (0.01kWh) {H19}')
print(f'H20 Yield total (0.01kWh) {H20}')
print(f'H21 Maximum power today (W) {H21}')
print(f'H22 Yield yesterday (0.01kWh) {H22}')
print(f'H23 Maximum power yesterday (W) {H23}')
print(f'ERR Error code {ERR}')
print(f'CS State of operation {CS}')
print(f'HSDS Day sequence number {HSDS}')
except:
V = "0"
VPV = "0"
PPV = "0"
I = "0"
IL = "0"
LOAD = "0"
H19 = "0"
H20 = "0"
H21 = "0"
H22 = "0"
H23 = "0"
ERR = "0"
CS = "0"
HSDS = "0"
print("Read serial fail")
data = date_stamp + "," + "Read serial fail" + "\n"
f = open('/home/pi/MPPT/MPPT_error_log.txt','a')
f.write(data)
f.close()
count += 1
# count > 300 is equal to 300 seconds or 5 minutes
if count > 300:
# Save data
data = date_stamp + "," + V + "," + VPV + "," + PPV + "," + I + "," + \
IL + "," + LOAD + "," + H19 + "," + H20 + "," + \
H21 + "," + H22 + "," + H23 + "," + ERR + "," + \
CS + "," + HSDS + "\n"
print(f'DATA = {data}')
f = open('/home/pi/MPPT/MPPT_data.txt','a')
f.write(data)
f.close()
print("Data saved")
count = 0
# Dweet data
try:
print("Preparing dweet")
dweet_dict = {}
dweet_dict.update({"V": str(V)})
dweet_dict.update({"VPV": str(VPV)})
dweet_dict.update({"PPV": str(PPV)})
dweet_dict.update({"I": str(I)})
dweet_dict.update({"IL": str(IL)})
dweet_dict.update({"LOAD": str(LOAD)})
dweet_dict.update({"H19": str(H19)})
dweet_dict.update({"H20": str(H20)})
dweet_dict.update({"H21": str(H21)})
dweet_dict.update({"H22": str(H22)})
dweet_dict.update({"H23": str(H23)})
dweet_dict.update({"ERR": str(ERR)})
dweet_dict.update({"CS": str(CS)})
dweet_dict.update({"HSDS": str(HSDS)})
dweet_dict.update({"Time": str(date_stamp)})
url = "https://dweet.io/dweet/for/3083-MPPT-Xbee1?"
x = requests.post(url, json=dweet_dict)
print(x.text)
except:
print("Dweet failed")
data = date_stamp + "," + "Dweet fail" + "\n"
f = open('/home/pi/MPPT/MPPT_error_log.txt','a')
f.write(data)
f.close()
# check dweet with - https://dweet.io/get/latest/dweet/for/3083-MPPT-Xbee1
# import and plot data text file
df = pandas.read_csv('/home/pi/MPPT/MPPT_data.txt')
fig = go.Figure(data = go.Scatter(mode='markers',
x=df.date_stamp,
y=df.V,
marker=dict(
color="LightSkyBlue",
size=20)
)
)
fig.update_layout(title="Voltage of Solar MPPT Battery (mV)",
xaxis_title = 'Time',
yaxis_title = 'Battery voltage (mV)',
font=dict(
size=20,
color="RebeccaPurple"
)
)
plotly.offline.plot(fig,
filename="/home/pi/MPPT/MPPT_data_plot.html",
auto_open=False)
print("Battery Voltage data plotted")
Modify the file MPPT_data.txt
- Modify the file MPPT_data.txt to include the following header date_stamp,V,VPV,PPV,I,IL,LOAD,H19,H20,H21,H22,H23,ERR,CS,HSDS
