Using a Raspberry Pi 3 to get information of two PZEM004T sensors which are connected to the Arduino Mega microcontroller

Using a Raspberry Pi 3 to get information of two PZEM004T sensors which are connected to the Arduino Mega microcontroller

21 août 2019 5 Par Richard

Hi everyone,

Today and for the end of my internship, i propose this tutorial to connect raspberry pi and 2 Pzem004T together.

All the sources are CC-BY-NC-SA https://creativecommons.org/licenses/by-nc-sa/3.0/fr/

Brief description:

The aim of this article is to explain how to get the voltage, current and power measured by two PZEM 004T sensors from a Raspberry Pi 3. The sensors are not directly connected to the Raspberry but they are connected to an Arduino microcontroller (Mega 2560) and this is connected to the Raspberry via USB cable. We first get all these values by using the arduino microcontroller and then we send them to the Raspberry. 

Procedure:

As stated before, the first step is to collect all the values from the Arduino microcontroller, so in order to do that we should use the library <PZEM004T.h>. This library can be downloaded from the webpage: https://github.com/olehs/PZEM004T as a zip package, then it should be added within the Arduino IDE as shown in the picture.

The next step is to connect the sensors to the arduino microcontroller. We will use the SoftwareSerial library to allow serial communication on other digital pins of the Arduino and be able to read more than one serial device. So, the RX and TX terminals of first sensor are connected to the pins 11 and 10 of the microcontroller and the RX and TX terminals of second sensor are connected to the pins 13 and 12 respectively.

Now, it is time to develop the code in Arduino IDE as follows:

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //* Code to get the voltage, current and power from two AC PZEM sensors connected to the Arduino Mega microcontroller, then all the values *//
 //  are concatenated in one char variable in order to send it through serial communication                                                 // 
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
 #include 
 #include 
  
 IPAddress ip(192,168,1,11);
 IPAddress ip1(192,168,1,10);
  
 char ix[10];
 char iy[10];
 char iz[10];
 char conc[360];
  
 char ix1[10];
 char iy1[10];
 char iz1[10];
  
 float V, V1;
 float i, i1;
 float p, p1;
  
 void setup() {
 Serial.begin (9600);
 }
  
 void loop() {
   
 PZEM004T pzem(10,11); //(RX TX)
 pzem.setAddress (ip);
 V=pzem.voltage(ip); //voltage obtained from the pzem library
 i = pzem.current(ip); //current obtained from the pzem library
 p = pzem.power(ip);//power obtained from the pzem library
 dtostrf(V,7,3,ix); //function used to stored the current value in the char variable ix, specifying 3 as the number of digits after the point
 dtostrf(i,7,3,iy); //function used to stored the current value in the char variable iy, specifying 3 as the number of digits after the point
 dtostrf(p,7,3,iz); //function used to stored the power value in the char variable iz, specifying 3 as the number of digits after the point
 delay(1000);
  
 PZEM004T pzem1(12,13); //(RX TX)
 pzem1.setAddress (ip1);
 V1=pzem1.voltage(ip1); //voltage obtained from the pzem library
 i1 = pzem1.current(ip1); //current obtained from the pzem library
 p1 = pzem1.power(ip1);//power obtained from the pzem library
 dtostrf(V1,7,3,ix1);//function used to stored the current value in the char variable ix1, specifying 3 as the number of digits after the point
 dtostrf(i1,7,3,iy1); //function used to stored the current value in the char variable iy1, specifying 3 as the number of digits after the point
 dtostrf(p1,7,3,iz1); //function used to stored the power value in the char variable iz1, specifying 3 as the number of digits after the point
 delay(1000);
  
 sprintf(conc,": %s, : %s, : %s, : %s, : %s, : %s,\n", ix,iy,iz,ix1,iy1,iz1); // function used to concatenate all the values in one unique char variable 
 Serial.write(conc);
  
 }  

Remarks:

  • The sensors are not read at the same time.
  • The type of the values given by the sensor is float.
  • After getting all the values these are converted from float to char type by using the “dtostrf” function in which the decimal places are limited to three.
  • All the 6 values are concatenated, using the function “sprintf”, in one unique char array and then it is sent as serial data.
  • Besides putting all the values together in the char array, we also put the ‘:’ and ‘,’ characters. In the end, the char array looks like: “: val1, : val2, : val3, : val4, : val5, : val6, :”. It is done in order to analyze and get the values easily in python.   

After uploading and testing the code on the microcontroller, it is time to deal with the python script. The Arduino microcontroller should be connected to the Raspberry by using a USB cable.

Before starting with the code, it could be good to know how to create a python file from the Linux terminal. It is done by typing the next command line:

touch PZEM_Sensors.py

Then to open the file already created, we should type the next command line:

nano PZEM_Sensors.py

The next screen will appear:

So now, let’s take a look at the code:

import serial
 import time
 import re
  
 port = "/dev/ttyACM0"
 s1 = serial.Serial(port,9600)
  
 while True:
     if s1.inWaiting()>0:
         inputValue = s1.readline().decode() 
         m = re.search('.*:(.*),.*:(.*),.*:(.*),.*:(.*),.*:(.*),.*:(.*),',inputValue) # command used to read the information and split it between the charcaters ':' and ','
         v1 = m.group(1).replace(" ","") ## command used to saved the information splitted before in a the variable 
         i1 = m.group(2).replace(" ","")
         p1 = m.group(3).replace(" ","")
         v2 = m.group(4).replace(" ","")
         i2 = m.group(5).replace(" ","")
         p2 = m.group(6).replace(" ","")
         a = float(v1)
         b = float(i1)
         c = float(p1)
         d = float(v2)
         e = float(i2)
         f = float(p2)
         print("Voltage1:",+a)
         print("Current1:",+b)
         print("Power1:",+c)
         print("Voltage2:",+d)
         print("Current2:",+e)
         print("Power2:",+f)  

Remarks:

  • We should specify the port of the Raspberry where the sensor is connected to. To know it, we should just type the next command from the LX Terminal window:  ls /dev –> The names of the connected USB devices start with: “ttyUSBX”. Where X indicates the number of each USB device connected.
  • The serial port is read and decoded to make sure we have a string of chars. It is done with the function readline() and decode() respectively.
  • All the six values are getting by using regular expressions. Using ‘.*:(.*),’, we take all the characters which are between ‘:’ and ‘,’ and then they are stored in groups.
  • In the end the values are converted from char to float type.  

After writing all the code and pressing the keys Ctrl + X you will be asked to save it or not. You should press the key y or n and then Enter.

To run the code, we should type the next command line:

python PZEM_Sensors.py

Then all the results and messages will appear in the Terminal windows or a message of error will appear if something wrong is inside the code.

The figure below shows all the results got from the two PZEM sensors. The current 1 is 0 due to there is not any current sensor connected to and for that the reason the power 1 is also 0. If there is any problem of communication the value, we will get is -1.

I hope this tutorial can help you,

Best regards,

Richard Flores Diaz