Smart Cities - Using a Raspberry Pi and Python to access Victron MPPT solar data
Jump to navigation
Jump to search
Introduction
This lesson will explain how to....
- Use Raspberry Pi OS Lite (no Desktop / GUI environment)
- Install a Virtual Environment for your Python applications
- Install python libraries to communication with Victron solar PV system monitoring equipment (VE.Direct)
- Write python code to communicate with the Victron hardware using USB serial communication
- Store data in a SQLite3 database
- Use systemd to execute applications at scheduled times
Authors
For more information contact Adam Simankowicz or Edmond Lascaris
Creating a Virtual Environment
- A Virtual Environment (venv) is a directory where independent python packages can be installed and used by specific python applications without interference from other packages or versions of python installed on the same machine.
- You can have different Virtual Environments installed, each tailored for specific python projects. [1].
Creating a Virtual Environment
- Navigate to a directory related to the python project.
- In this example we will create a directory in the home directory named solar_python
- Install the python3-venv python package with the command sudo apt-get install python3-venv.
- Within the directory run the command python3 -m venv /home/pi/solar_python/venv
- A new folder venv will be installed in your project working directory which contains a number of other files.
- This Virtual Environment (venv) directory is where python modules can be installed.
- To activate the Virtual Environment the linux source command is used [2].
- Enter the command source /home/pi/solar_python/venv/bin/activate
- Commands such as ./activate or ./venv/bin/activate will not work.
- The deactivate command is used to escape from the Virtual Environment.
- We will use this Virtual Environment to install specific python modules required for our project.
VE.Direct Python Library Installation
- VE-Direct is a serial communication protocol used by the Victron MPPT Charge Control unit that can be used by computers such as the Raspberry Pi to extract data on the performance of the unit and system.
- A python library is available at these Github addresses
https://github.com/jmfife/vedirect
https://github.com/karioja/vedirect
To install this VEDirect python library:
- Install git with the command sudo apt install git
- Enter the project directory solar_python
- Ensure that the venv Virtual Environment is activated with the command source /venv/bin/activate
- To install the python library enter the command
python3 -m pip install "git+https://github.com/jmfife/vedirect"
- For some reason the installation only works by dropping the examples from the install.
- The original github is shown below.
- The installation of VE.Direct can be tested with the command vedirect
- The VEDirect python library can be found in the directory /home/pi/solar_python/venv/lib/python3.9/site-packages
USB Ports
- The VE.Direct USB cable that is connected to the Victron MPPT is plugged into a Raspberry Pi USB port.
- To find out which port is used enter the command ls /dev/*USB*
- It shows that only port ttyUSB0 is currently used. This must be connected to the Victron MPPT.
- More information is available on how to use the VE.Direct Protocol at the Victron web site [3]. You need to enter your email address to download the file.
- To run VEDirect end the command vedirect and the port that the VEDirect USB cable is connected to.
- The instruction is shown in the github [4].
- The command will then show repeated outputs from the Victron MPPT unit.
- Note that the port will be /dev/ttyUSB0
Interpretation of Victron Unit outputs
- The VE.Direct Protocol reference documentation gives a reference for each data label.
- This reference document can be used for:
- MPPT Charge Controller - to monitor the output from the solar PV panel and charge state of the battery.
- BMV71x Smart Shunt - to monitor current inputs and outputs from the battery and State of Charge of the battery.
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.
Reading Data from Victron MPPT using Python
- Using nano create a test file named victron_data_test.py with the command nano victron_test_data.py
- In nano enter the following python program.
- Note that the USB port may be different on your computer.
- Save the file and exit nano.
- To make the file executable enter the command sudo chmod +x victron_test_data.py
- Activate the Virtual Environment (venv) with the command source venv/bin/activate
- Remember that we installed the python library in the venv container.
- Then execute the python program with the command python3 victron_test_data.py
- In addition to printing out a full readout of the data (once) the program will also print out the V (battery voltage) data.
- In this case the battery voltage (mV) is 13280.
Scheduling python scripts with Cron
- Cron is a scheduling program that can execute programs at regular time intervals.
- It is normally used for running server backups.
- In this example we will use cron to run our python script.
- To open cron click on the Terminal and enter crontab -e
- The option -e is short for edit
- The first time you start cron it will ask which default editor to use.
- Choose nano
- When the nano editor for cron opens most of the initial content are comments.
- Instructions are given on how to write tasks in cron.
- A tak must have a scheduled time and a command
- In this first example the schedule time is 5 minutes past the hour, every hour
- Using the scheduling template minutes(0-59), hours (0-23), day of month (0-30), month (0-11), day of week (0-6)
- To set the schedule for 5 minutes past the hour, every hour
- 5 * * * * - which translates to:
- 05 minutes past the hour
- * every hour
- * every day
- * every month
- * every day of the week
- The command is /home/pi/solar_python/venv/bin/python /home/pi/solar_python/victron_data.py
- Save the file in nano.
- The task will run automatically as soon as the file is closed.
- To list the cron tasks enter the command crontab -l
- If the task needs to run every 15 minutes at times 5, 20, 35, and 50 then the schedule is represented as 5, 20, 35, 50 * * * *
systemd Timers - an alternative to cron
To run a unit at specified times or intervals you need two units[5]:
- a service unit that defines what program to run
- a timer unit that defines when to run the service unit
- Both the timer unit and the service unit have the same name (e.g.foo.timer and foo.service).
- The time unit starts the service unit
- Ideally we want this program to run every 15 minutes to capture MPPT data.
- Events can be scheduled using cron, however cron has some limitations and new timing dependent functions now use systemd
- systemd services are found in the directory /etc/systemd/system
- Some example services have already been created:
- solar-vedirect-comms.service
- solar-vedirect-comms.timer
- The listing for solar-vedirect-comms.service is reproduced below.
- Here is the listing for solar-vedirect-comms.timer
systemd service status
- To see a status update on a systemd service enter the command systemctl status solar-vedirect-comms.service
- And the status of the systemd timer is obtained with the command systemctl status solar-vedirect-comms.timer
systemctl daemon-reload
- If there are any changes to the systemd files then the systemd service needs to be reloaded.
- Enter the command sudo systemctl daemon-reload
enable and start systemctl service
- If the status indicates an error it may be necessary to enable and start the service again.
- Enter the commands sudo systemctl enable solar-vedirect-comms.timer. This commands simply enables auto-start at boot time (but doesn't start the unit yet)
- To start the timer enter the command sudo systemctl start solar-vedirect-comms.timer. This will start the timer immediately.
- A complete system reboot may also be required with the command sudo reboot now
Testing a simple systemd Timer
Create a demonstration python file
- Navigate to the directory in your home directory where you created a Virtual Environment (venv) for python. We will test this environment.
- On this computer the path to the venv is /home/pi/solar_python/
- Using nano create a python file named test_systemd.py that will printHello solar_python
- Enter the command nano test_systemd.py
- Enter the following code in the nano editor screen.
- #!/home/pi/solar_python/venv/bin/python is the path to the python Virtual Environment
- Save the changes using Ctrl + X
- Check that the file has been created.
- Also note that the file does not have executable file permissions set [6].
- To make the file executable enter the command sudo chmod +x test_systemd.py
- Note that file permissions do not have to be changed to executable. Only change file permissions if there are issues.
- Technically this file is not executed directly. The text in the file serves as a script only and is interpreted rather than executed.
- Now you can execute (run) the file with the command python test_systemd.py
Create a systemd service
- Open the Terminal and navigate to /etc/systemd/system
- Using nano create a file named test_systemd.service with the command sudo nano test_systemd.service
- Enter the following code in the nano editor.
- Check that the file has been created.
- Enter the command ls -l to check the permissions of the file.
- Note that the file is not set as executable in the permission settings [7].
- Enter the command sudo chmod +x test_system.service to change to permission settings to executable
- Note that file permissions do not have to be changed to executable. Only change file permissions if there are issues.
- Technically this file is not executed directly. The text in the file serves as a script only and is interpreted rather than executed.
- Verify that the permission settings have been updated with the command ls -l
Create a systemd timer
- Navigate to the directory /etc/systemd/system
- To create the Timer unit enter the command sudo nano test_systemd.timer
- Enter the following code in the nano editor.
- Check the file test_systemd.timer has been created.
- Change the file permissions with the command sudo chmod +x test_systemd.timer
- Note that file permissions do not have to be changed. Only change file permissions if there are issues.
- Technically this file is not executed directly. The text in the file serves as a script only and is interpreted rather than executed.
- Check that the file permissions have been updated.
Initiating the Timer
- The following order of execution of commands is recommended:
- sudo systemctl daemon-reload - makes systemd aware that changes to files has occured
- systemctl enable foo.timer - This commands simply enables auto-start at boot time (but it doesn't start the timer unit yet). Do not enable the service unit because that would mean to start the service at boot time. The Timer unit will control (start) the Service unit.
- systemctl start foo.timer - This will start the timer unit.
- systemctl status foo.timer foo.service - To see the status of both the Timer unit and the Service Unit.
Good sytemctl status readout
- If the system is working correctly a status report will look like the following.
- The command entered to see the system status is systemctl status test_systemd.timer test_systemd.system
systemctl daemon-reload
- This makes systemd reload the Service and Timer unit files and to re-consider their dependencies
- systemd caches these files so whenever you change a unit file, this command is required.
- Enter the command sudo systemctl daemon-reload
systemctl enable foo.timer and systemctl start foo.timer
- The command sudo system enable foo.timer enables auto-start at boot time (but doesn't start the unit yet).
- The foo.timer will engage next time the computer is rebooted.
- Do not enable the service unit because that would mean to start the service at boot time (regardless of any timer settings).
- The command sudo start foo.timer will start the foo.timer. The timer unit will start the service unit whenever the set time is due.
- Check the status of the foo.timer with the command sudo systemctl foo.timer
Cheat Sheet
- systemctl enable/disable controls the behaviour when booting. Only enable and start the timer unit, not the service unit
- systemctl start/stop controls the behaviour right now
- systemctl daemon-reload whenever you edit the unit files
- systemctl status to print out the current status of the units. Useful for monitoring trigger times and logs
Storing data to sqlite3 database
- SQLite is a SQL database that exists on a computer as a single file.
- The single file format makes the database easier to share and backup.
- The intention is for this database (and the data it contains) to be available to students so that they can gain experience analysing the data.
- SQLite will be used on a Raspberry Pi to store data from the Victron MPPT Charge Controller and Victron SmartShunt.
Installing SQLite on Raspberry Pi
- To install SQLite on a Raspberry Pi use the command sudo apt install sqlite3 [8]
- SQLite3 is the current version of SQLite.
- You can confirm the version of SQLite3 installed with the command sqlite3 --version
SQLite Browser software
- Follow this link to install and operate the sqlitebrowser software on the Raspberry Pi Smart_Cities_-_SQLite3_database
- Click on Create Table and name it measurements
- Click on the table measurements and then click on the Modify Table tab.
- In the Edit table definition window you can see individual data fields and the type and rules applied to each field.
- Fields include:
- id - unique number for each data row. An INTEGER number. Not null (No). Auto Increment (AI). Primary Key (PK).
- timestamp - this records the time of the data entry. Date is encoded as universal time. The time is recorded as TEXT. This cell must not be empty (Not Null).
- V - Voltage of the battery (mV). INTEGER.
- VPV - Solar panel voltage (mV). INTEGER.
- PPV - Power output from the Solar Panel (Watts). INTEGER.
- I - current from the MPPT charge controller to the battery (mA). INTEGER.
- H19 - Total yield from the MPPT controller in kiloWatt hours (0.01 kWh). INTEGER.
- H20 - Yield today (0.01 kWh). INTEGER.
- H21 - Maximum power today (W). INTEGER.
- H22 - Yield yesterday (0.01 kWh). INTEGER.
- H23 - Maximum power yesterday (W). INTEGER.
- ERR - Error codes. Normally 0 when operating correctly. INTEGER.
- CS - Charge state of battery (3-Bulk, 4-Absorption and 5-Float modes). INTEGER.
- MPPT - MPPT tracker operation status. INTEGER.
- Most fields are numeric (INTEGER).
- Only the timestamp is TEXT. Programs interacting with the database will automatically be able to interpret this text as universal time.
- Even errors or status messages are numeric and the Victron VE.Direct Protocol manual is used for decoding.
Python SQLite
- In addition to using sqlitebrowser software you can install a python module to allow a python application to interact with a SQLite database [9].
- A Python Application can even create the SQLite table from scratch.
SQL script to create a Database Table within a Python application
- The measurements table that we previously examined can also be created by running SQL commands from within Python script.
- The previous database provides some script that we can copy and use in our own python application. Shown below.
- CREATE TABLE "measurements" ( "id" INTEGER NOT NULL, "timestamp" TEXT NOT NULL, "V" INTEGER, "VPV" INTEGER, "PPV" INTEGER, "I" INTEGER, "H19" INTEGER, "H20" INTEGER, "H21" INTEGER, "H22" INTEGER, "H23" INTEGER, "ERR" INTEGER, "CS" INTEGER, "MPPT" INTEGER, PRIMARY KEY("id" AUTOINCREMENT));
- The SQL command contains all instructions for the creation of the table and each individual field entry and the characteristics for each field.
- We will use this script in a python application to create this database from scratch.
Connecting to SQLite3 Database using Python
- See the tutorial [SQLite database tutorial]
Python code for Victron VE.Direct connected to Victron MPPT
#!/home/pi/solar_python/venv/bin/python
from datetime import datetime
from vedirect import VEDirect
import sqlite3
port_mppt = '/dev/ttyUSB0'
port_shunt = '/dev/ttyUSB1'
timeout = 60
# Initiate VEDirect serial objects
ve_mppt = VEDirect(port_mppt, timeout, '')
# ve_shunt = VEDirect(port_shunt, timeout, '')
data_mppt = ve_mppt.read_data_single()
# data_shunt = ve_shunt.read_data_single()
# print(data_mppt)
data = {}
##########################################
#V =
field_labels_mppt = [
'V',
'VPV',
'PPV',
'I',
'H19',
'H20',
'H21',
'H22',
'H23',
'ERR',
'CS',
'MPPT',
]
field_labels_shunt = []
# Loop through the field list above and retrieve each piece of data and put it in a dict
for label in field_labels_mppt:
data.update({label: int(data_mppt[label])})
# for label in field_labels_shunt:
# data.update({label: int(data_shunt[label])})
# Generate timestamp, get rid of microseconds (unneeded)
# and add Zulu time indicator on the end
now_unformatted = datetime.utcnow().isoformat()
now = f"{now_unformatted[:-7]}Z"
try:
con = sqlite3.connect('data.db')
c = con.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS "measurements" (
"id" INTEGER NOT NULL,
"timestamp" TEXT NOT NULL,
"V" INTEGER,
"VPV" INTEGER,
"PPV" INTEGER,
"I" INTEGER,
"H19" INTEGER,
"H20" INTEGER,
"H21" INTEGER,
"H22" INTEGER,
"H23" INTEGER,
"ERR" INTEGER,
"CS" INTEGER,
"MPPT" INTEGER,
PRIMARY KEY("id" AUTOINCREMENT));""")
insert_query = """INSERT INTO measurements (
timestamp,
V,
VPV,
PPV,
I,
H19,
H20,
H21,
H22,
H23,
ERR,
CS,
MPPT
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?);"""
insert_data = (
now,
data['V'],
data['VPV'],
data['PPV'],
data['I'],
data['H19'],
data['H20'],
data['H21'],
data['H22'],
data['H23'],
data['ERR'],
data['CS'],
data['MPPT']
)
c.execute(insert_query, insert_data)
con.commit()
select_query = "SELECT * FROM measurements;"
c.execute(select_query)
result = c.fetchall()
print(f"result={result}")
c.close()
except sqlite3.Error as error:
print("Error while connecting to sqlite", error)
finally:
if con:
con.close()
print("The SQLite connection is closed")
Publishing data using Dweet
- To publish data to dweet we need to add the following python code.
- The code:
- creates an empty python dictionary dweet_dict
- added the current time as the first entry dweet_dict.update({"latest_update": now})
- then combines the dweet url and dweet_dict and sends a request x = requests.post(url, json=dweet_dict)
import requests
# dweet data
dweet_dict = {}
dweet_dict = data
dweet_dict.update({"latest_update": now})
url = "https://dweet.io/dweet/for/<your_dweet_project_name>?"
x = requests.post(url, json=dweet_dict)
print(x.text)
# check dweet with - https://dweet.io/get/latest/dweet/for/<your_dweet_project_name>
Python code for victron_data.py has been collapsed by default. Click here to expand:
#!/home/pi/solar_python/venv/bin/python3
from datetime import datetime
from vedirect import VEDirect
import sqlite3
import requests
port_mppt = '/dev/ttyUSB0'
port_shunt = '/dev/ttyUSB1'
timeout = 60
# Initiate VEDirect serial objects
ve_mppt = VEDirect(port_mppt, timeout, '')
# ve_shunt = VEDirect(port_shunt, timeout, '')
data_mppt = ve_mppt.read_data_single()
# data_shunt = ve_shunt.read_data_single()
# print(data_mppt)
data = {}
##########################################
#V =
field_labels_mppt = [
'V',
'VPV',
'PPV',
'I',
'H19',
'H20',
'H21',
'H22',
'H23',
'ERR',
'CS',
'MPPT',
]
field_labels_shunt = []
# Loop through the field list above and retrieve each piece of data and put it in a dict
for label in field_labels_mppt:
data.update({label: int(data_mppt[label])})
# for label in field_labels_shunt:
# data.update({label: int(data_shunt[label])})
# Generate timestamp, get rid of microseconds (unneeded)
# and add Zulu time indicator on the end
now_unformatted = datetime.utcnow().isoformat()
now = f"{now_unformatted[:-7]}Z"
try:
con = sqlite3.connect('data.db')
c = con.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS "measurements" (
"id" INTEGER NOT NULL,
"timestamp" TEXT NOT NULL,
"V" INTEGER,
"VPV" INTEGER,
"PPV" INTEGER,
"I" INTEGER,
"H19" INTEGER,
"H20" INTEGER,
"H21" INTEGER,
"H22" INTEGER,
"H23" INTEGER,
"ERR" INTEGER,
"CS" INTEGER,
"MPPT" INTEGER,
PRIMARY KEY("id" AUTOINCREMENT));""")
insert_query = """INSERT INTO measurements (
timestamp,
V,
VPV,
PPV,
I,
H19,
H20,
H21,
H22,
H23,
ERR,
CS,
MPPT
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?);"""
insert_data = (
now,
data['V'],
data['VPV'],
data['PPV'],
data['I'],
data['H19'],
data['H20'],
data['H21'],
data['H22'],
data['H23'],
data['ERR'],
data['CS'],
data['MPPT']
)
# dweet data
dweet_dict = {}
dweet_dict = data
dweet_dict.update({"latest_update": now})
url = "https://dweet.io/dweet/for/your-dweet-project-name?"
x = requests.post(url, json=dweet_dict)
print(f"x data {x.text}")
c.execute(insert_query, insert_data)
con.commit()
select_query = "SELECT * FROM measurements;"
c.execute(select_query)
result = c.fetchall()
#print(f"result={result}")
c.close()
except sqlite3.Error as error:
print("Error while connecting to sqlite", error)
finally:
if con:
con.close()
print("The SQLite connection is closed")
- The Terminal output would be similar to the following.
Install requests python module
- The requests library needs to be installed in the virtual environment so that data can be sent to dweet.
- In the Terminal navigate to the folder containing the python virtual environment venv
- Activate the virtual environment with the command source venv/bin/activate
- Install requests using pip (pip installs python) with the command python -m pip install requests
- Test that the requests library is installed by running the python program.
- When installation is complete exit the virtual environment with the command deactivate
Accessing the Remote Computer using SSH
Ping the Remote Computer
- In the Terminal use the ping command to check to see if the remote computer can be accessed on the network.
- In this example the command ping 192.168.1.122 was used.
SSH - Use Secure Shell to access the Remote Computer
- In this instance the command entered was ssh -p 1099 pi@192.168.1.122 -i /Users/edmond/.ssh/solar-pi
- Now the remote computer has full access host computer using SSH.
- All interactions are via the Terminal and command line.
SSH - Run a Python Program in VENV
- Navigate to the directory with the venv folder.
- To start the Virtual Environment enter the command source /home/pi/solar_python/venv/bin/activate
- Notice that the (venv) appears at the beginning of the command line.
- To deactivate the Virtual Environment enter the command deactivate
- Install python libraries and run python programs when the Virtual Environment is active.
- Executing a python program
Secure Copy (scp) Files From Remote to Local using Public and Private keys
- Secure Copy (scp) works the same way but with a few Options added to the instruction.
- -P the Port may need to be specified
- -i the path to the private key on the Local computer
- IP address of the remote computer
- path and file name for the file on the remote computer
- In this example the file on the remote computer is located at /home/pi/solar_python/data.db
- To copy the file from the remote computer enter the command scp -P 1099 -i /Users/edmond/.ssh/solar-pi pi@110.175.190.102:/home/pi/solar_python/data.db .
- -P 1099 is the port
- -i /Users/edmond/.ssh/solar-pi is the location of the Private key on the Local computer
- pi@110.175.190.102 is the IP address of the Remote computer
- :/home/pi/solar_python/data.db is the path to the file on the Remote computer
- . (dot) indicates to copy the file to the current working directory on the Local computer. We could specify any path and also a new file name for the copied file.
- Files are copied to the local computer into the same directory where the secure copy (scp) command was executed.
- More information on Secure Copy is available here [10]
Saving solar-pi data using Node-RED
Cronplus Node
HTTP Request Node
Function Node - Save Data
Write File Node - Save solar-pi-dweet-data.txt
Node-RED Flow JSON
Node-RED JSON flow. Click here to expand:
[
{
"id": "d5c985a87833f305",
"type": "tab",
"label": "solar-pi",
"disabled": false,
"info": "",
"env": []
},
{
"id": "b02e844b7995799a",
"type": "function",
"z": "d5c985a87833f305",
"name": "Save data function",
"func": "var V; // battery voltage data (mV)\nvar VPV; // solar panel voltage (mV)\nvar PPV; // solar panel power (Watts)\nvar I; // current entering battery from solar panel (mA)\nvar H19; // yield total (0.01 kWh)\nvar H20; // yield today (0.01 kWh)\nvar H21; // maximum power today (W)\nvar H22; // yield yesterday (0.01 kWh)\nvar H23; // maximum power yesterday (W)\nvar ERR; // error codes\nvar datetime; // humidity in sensor housing\n\nV = msg.payload.with[0].content.V;\nVPV = msg.payload.with[0].content.VPV;\nPPV = msg.payload.with[0].content.PPV;\nI = msg.payload.with[0].content.I;\nH19 = msg.payload.with[0].content.H19;\nH20 = msg.payload.with[0].content.H20;\nH21 = msg.payload.with[0].content.H21;\nH22 = msg.payload.with[0].content.H22;\nH23 = msg.payload.with[0].content.H23;\nERR = msg.payload.with[0].content.ERR;\ndatetime = msg.payload.with[0].content.latest_update;\n\nmsg.payload = String(msg.myepoch) + \",\" + String(msg.mydate) + \",\"\n + String(msg.mytimes) + \",\" + String(V) + \",\" + String(VPV) + \",\" \n + String(PPV) + \",\" + String(I) + \",\" + String(H19) + \",\" \n + String(H20) + \",\" + String(H21) + \",\" + String(H22) + \",\"\n + String(H23) + \",\" + String(ERR) + \",\" + String(datetime);\nreturn [msg];",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 170,
"y": 280,
"wires": [
[
"2f7b0bf44d9f5b93"
]
]
},
{
"id": "69d41e9640f94bc9",
"type": "http request",
"z": "d5c985a87833f305",
"name": "",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "https://dweet.io/get/latest/dweet/for/dweet-project-name",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"senderr": false,
"x": 610,
"y": 160,
"wires": [
[
"3a55f787080947c7",
"b02e844b7995799a"
]
]
},
{
"id": "99d0c88bb2d29af4",
"type": "debug",
"z": "d5c985a87833f305",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 630,
"y": 280,
"wires": []
},
{
"id": "0d5473c1cacc1355",
"type": "cronplus",
"z": "d5c985a87833f305",
"name": "10,25,40,55 hourly",
"outputField": "payload",
"timeZone": "",
"persistDynamic": false,
"commandResponseMsgOutput": "output1",
"outputs": 1,
"options": [
{
"name": "schedule1",
"topic": "topic1",
"payloadType": "default",
"payload": "",
"expressionType": "cron",
"expression": "10,25,40,55 * * * * ",
"location": "",
"offset": "0",
"solarType": "all",
"solarEvents": "sunrise,sunset"
}
],
"x": 170,
"y": 160,
"wires": [
[
"4ac0ce7653fbbd80"
]
]
},
{
"id": "4ac0ce7653fbbd80",
"type": "simpletime",
"z": "d5c985a87833f305",
"name": "",
"mydate": true,
"myymd": true,
"myyear": true,
"mymonth": true,
"mymonthn": true,
"mydom": true,
"mydoy": true,
"myday": true,
"myhourpm": true,
"myhour": true,
"mytime": true,
"mytimes": true,
"myminute": true,
"myminutes": true,
"mysecond": true,
"mymillis": true,
"myepoch": true,
"myrawdate": true,
"mypm": true,
"x": 390,
"y": 160,
"wires": [
[
"69d41e9640f94bc9"
]
]
},
{
"id": "2f7b0bf44d9f5b93",
"type": "file",
"z": "d5c985a87833f305",
"name": "solar-pi-dweet-data",
"filename": "/home/pi/SolarPi/solar-pi-dweet-data.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "false",
"encoding": "none",
"x": 410,
"y": 280,
"wires": [
[
"99d0c88bb2d29af4"
]
]
},
{
"id": "3a55f787080947c7",
"type": "debug",
"z": "d5c985a87833f305",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 650,
"y": 80,
"wires": []
}
]