Heltec-MiniLoRa with PZEM-004T-V3

เดิมทีออกแบบ MiniLoRa มาเน้นใช้านเป็นเครื่องวัด RS485 จากระบบฟาร์ม  แต่ก็มีคำถามเรื่องการใช้วัดไฟฟ้า ด้วย PZEM-004T V3  เลยต้องมาทบทวนกันหน่อยว่าจะต้องใช้ขาไหนบน บอร์ดนี้
สรุปจะให้ใช้ PZEM-oo4T RX, TX ที่ขา  D9, D10 ของ  Nano  ซึ่ง  บนบอร์ดนี้ Nano จะใช้ D5, D6 ต่อ Serial กับ Heltec ทางขา 17,13

#include <EEPROM.h>
///// Add on Aug 11 2020
#include <PZEM004Tv30.h>
/* Use software serial for the PZEM
 * Pin 11 Rx (Connects to the Tx pin on the PZEM)
 * Pin 12 Tx (Connects to the Rx pin on the PZEM)
*/
#include <SoftwareSerial.h>
SoftwareSerial chat(5, 6); // RX, TX  to Heltec LoRa (5 , 6 )
////////
#include <SHT1x.h>
#define dataPin  A0  //A4
#define clockPin A1  //A5
SHT1x sht1x(dataPin, clockPin);
///////
int relay1 = 8;
#define FlowSwitch 11
int analogPin = A1;
int val = 0;
int pzemtime= 2000;
////
PZEM004Tv30 pzem(10, 9); // 12,10
////
#include <math.h>
uint32_t delayMS;
////////
//// ph asset //
const int analogPhPin = A0; //PH module pin P0 connected to analog pin A0
long phTot, temTot;
float phAvg, temAvg;
float pHValue;
int x;
float C = 25.85; // 25.85 Constant of straight line (Y = mx + C)
float m = -6.8; // -6.8 Slope of straight line (Y = mx + C)
///
int i;
int sensorValue;
float rainmm ;
float dustDensity = 35;
String response ="0";
String response_c = "0";
String a ;
float temp_0 = 0;
float tempF_0 = 0;
float humid_0 = 0;
float vHumidity = 0;
float vTemperature = 0;
String data1 ;
String data2 ; // standard
float data3 = 0;
float data4 = 0;
float data5 = 0;
float data6 = 0;
float data7 = 0;
float data8 = 0;
float data9 = 0;
String sdata1 ;
String sdata2 ;
String sdata3 ;
String sdata4 ;
String sdata5 ;
String sdata6 ;
String sdata7 ;
String sdata8 ;
String FlowLowStatus ;
float data18 = 0;
float data19 = 0;
float data20 = 0;
float temperatureC = 0;
float temperatureF = 0;
int counter = 1;
int sentcount = 0;
float vPower=0;
float vVolt=0;
float iamp=0;
float vEnergy=0;
//////////////////////////////
void setup()  {
  Serial.begin(9600);
  chat.begin(57600);
  pinMode(relay1, OUTPUT); // sets the pin as output
  pinMode(FlowSwitch,INPUT); // set as input flow switch
}
void loop() {
  sht1_loop();
  FlowSwitchLow();
  pH_loop();
  chat.begin(57600);
  if (chat.readString()){
     // chat.print(1);
     if(chat.readString()== "Input1"){
      chat.print(String(data3));
     }
     if(chat.readString()== "Input2"){
     chat.print(String(data4));
     }
     if(chat.readString()== "Input3"){
      chat.print(String(data5));
     }
     if(chat.readString()== "Input4"){
     chat.print(String(data6));
     }
     if(chat.readString()== "Input5"){
     chat.print(String(data7));
     }
     Serial.print("Sent done data no : ");
     Serial.println(i);
  }
  i++;
  pzemV3Loop();
}
void sht1_loop()
{
  float temp_c; //
  float temp_f; //
  float humidity; //
  temp_c = sht1x.readTemperatureC();
  temp_f = sht1x.readTemperatureF();
  humidity = sht1x.readHumidity();
  data3 = temp_c;
  data4 = humidity;
  Serial.print("Temperature: ");
  Serial.print(temp_c, DEC);
  Serial.print("C / ");
  Serial.print(temp_f, DEC);
  Serial.print("F. Humidity: ");
  Serial.print(humidity);
  Serial.println("%");
  if (temp_c < 27  ) { //
    //digitalWrite(relay3, HIGH); //
  }
  else {
    //digitalWrite(relay3, LOW); //
  }
  if (humidity < 55  ) { //
    //digitalWrite(relay4, HIGH); //
  }
  else {
    //digitalWrite(relay4, LOW); //
  }
  delay(100);
}
void pH_setup()
{
}
void pH_loop() {
  phTot = 0;
  temTot = 0;
  phAvg = 0;
  temAvg = 0;
  //taking 10 sample and adding with 10 milli second delay
  for(x=0; x<10 ; x++)
    {
        phTot += analogRead(A0);
        temTot += analogRead(A1);
        delay(10);
    }
    float temAvg = temTot/10;
    float phAvg = temTot/10;
   // float temVoltage = temAvg * (5000.0 / 1023.0); //convert sensor reading into milli volt
    float phVoltage =  phAvg * (5.0 / 1023.0); //convert sensor reading into milli volt
 //   float Etemp = temVoltage*0.1; //convert milli volt to temperature degree Celsius
  pHValue = phVoltage*m+C;
  Serial.print("phVoltage = ");
  Serial.print(phVoltage);
  Serial.print(" ");
  Serial.print("pH=");
  Serial.println(pHValue);
  data5 = pHValue;
 if (pHValue < 7.5  ) { //
    //digitalWrite(relay1, HIGH); //
  }
  else {
    //digitalWrite(relay1, LOW); //
  }
  if (pHValue > 9.0  ) { //
    //digitalWrite(relay2, HIGH); //
  }
  else {
    //digitalWrite(relay2, LOW); //
  }
  delay(1000);
}
void FlowSwitchLow()
{
  FlowLowStatus = String(digitalRead(FlowSwitch));
  Serial.println("Flow Sensor :"+ FlowLowStatus);
}
void pzemV3Loop() {
    float vVolt = pzem.voltage();
    if( !isnan(vVolt) ){
        Serial.print("Voltage: "); Serial.print(vVolt); Serial.println("V");
    } else {
        Serial.println("Error reading voltage");
    }
    float iamp = pzem.current();
    if( !isnan(iamp) ){
        Serial.print("Current: "); Serial.print(iamp); Serial.println("A");
    } else {
        Serial.println("Error reading current");
    }
    float vEnergy = pzem.power();
    if( !isnan(vEnergy) ){
        Serial.print("Power: "); Serial.print(vEnergy); Serial.println("W");
    } else {
        Serial.println("Error reading power");
    }
    float energy = pzem.energy();
    if( !isnan(energy) ){
        Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
    } else {
        Serial.println("Error reading energy");
    }
    float frequency = pzem.frequency();
    if( !isnan(frequency) ){
        Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz");
    } else {
        Serial.println("Error reading frequency");
    }
    float pf = pzem.pf();
    if( !isnan(pf) ){
        Serial.print("PF: "); Serial.println(pf);
    } else {
        Serial.println("Error reading power factor");
    }
  data6 = vVolt;
  data7 = iamp;
  data8 = vEnergy;
  data9 = pf;
    Serial.println();
    delay(2000);
}
void PumpARun()
{
  digitalWrite(relay1,HIGH);
  Serial.println("Pump A Run ");
}
void RequestDataSet()
{
Serial.println("Please wait while Request dataset from Wemos ..");
String b = "";
  while (b == "") {
    chat.print("TempH"); //
    b = chat.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer for Temp High : = ");Serial.println(b);
  //data0 = String(b);
  delay(1000);
  b="";
  while (b == "") {
    chat.print("HumidH"); //
    b = chat.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer for Humid High : = ");Serial.println(b);
  //data0 = String(b);
  delay(1000);
  b="";
  a="";
}

และ  Heltec Code ตามนี้เลยครับ

/*
  Code file name : MiniLoRa-Nano-Node-Dev-184...Trial Seria
  This is a simple example show the Heltec.LoRa sended data in OLED.
  The onboard OLED display is SSD1306 driver and I2C interface. In order to make the
  OLED correctly operation, you should output a high-low-high(1-0-1) signal by soft-
  ware to OLED's reset pin, the low-level signal at least 5ms.
  OLED pins to ESP32 GPIOs via this connecthin:
  OLED_SDA -- GPIO4
  OLED_SCL -- GPIO15
  OLED_RST -- GPIO16
  by Aaron.Lee from HelTec AutoMation, ChengDu, China
  成都惠利特自动化科技有限公司
  www.heltec.cn
  this project also realess in GitHub:
  https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
*/
#include "ModbusMaster.h" //https://github.com/4-20ma/ModbusMaster
/*!
  We're using a MAX485-compatible RS485 Transceiver.
  Rx/Tx is hooked up to the hardware serial port at 'Serial'.
  The Data Enable (DE) and Receiver Enable (RE) pins are hooked up as follows:
*/
#include <Arduino.h>
#include <Wire.h>
#include <math.h>
#include <ArduinoJson.h>
#define RXX 17
#define TXX 13
#include <Adafruit_Sensor.h>
#include <DHT.h>  // กรณีนี้ต้องใช้คู่กันกับ  DHT_U.h
#include <DHT_U.h>
#define DHTPIN  2 // Pin which is connected to the DHT sensor.
//#define DHTTYPE   DHT22     // DHT 22 (AM2302)
#define DHTTYPE   DHT21     // DHT 21 (AM2301)
// See guide for details on sensor wiring and usage:
//   https://learn.adafruit.com/dht/overview
DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
#define MAX485_RE_NEG  25 //D4 RS485 has a enable/disable pin to transmit or receive data. Arduino Digital Pin 2 = Rx/Tx 'Enable'; High to Transmit, Low to Receive
#define Slave_ID1    1  // see dip swith if connect to Transpower
#define RX_PIN      22  //RX2 22 do not change
#define TX_PIN      23  //TX2 23 do not change
#include "heltec.h"
#include "images.h"
#define BAND    915E6  //you can set band here directly,e.g. 868E6,915E6,433E6
// instantiate ModbusMaster object
ModbusMaster modbus;
double res_dbl0;
double res_dbl1;
double res_dbl ;
unsigned int counter = 0;
String rssi = "RSSI --";
String packSize = "--";
String packet ;
String datasend ;
String datasend1 ;
String datasend2 ;
String data2 ;
String data3 ;
String data4 ;
String data5 ;
String data6 ;
String data7 ;
String data8 ;
String data9 ;
String a ;
float temp_0 = 0;
float humid_0 = 0;
float vHumidity = 0;
float vTemperature = 0;
String data1="197";
String cccode = "67ujsevebdh5";
long lastMillis = 100;
// Convent 32bit to float
//------------------------------------------------
float HexTofloat(uint32_t x)
{
  return (*(float*)&x);
}
uint32_t FloatTohex(float x)
{
  return (*(uint32_t*)&x);
}
//------------------------------------------------
//===
void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, HIGH); //Switch to transmit data
}
void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, LOW); //Switch to receive data
}
//====
void logo()
{
  Heltec.display->clear();
  Heltec.display->drawXbm(0,5,logo_width,logo_height,logo_bits);
  Heltec.display->display();
}
void RS485_setup()
{
  pinMode(MAX485_RE_NEG, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, LOW);
  // Modbus communication runs at 9600 baud
  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); // serial can be no1 , no 2  8N1
  modbus.begin(Slave_ID1, Serial1);
  // Callbacks allow us to configure the RS485 transceiver correctly
  modbus.preTransmission(preTransmission);
  modbus.postTransmission(postTransmission);
}
void setup()
{
  //WIFI Kit series V1 not support Vext control
  Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.Heltec.Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/);
  Heltec.display->init();
  Heltec.display->flipScreenVertically();
  Heltec.display->setFont(ArialMT_Plain_10);
  logo();
  delay(1500);
  Heltec.display->clear();
  Heltec.display->drawString(0, 0, "Heltec.LoRa Initial success!");
  Heltec.display->display();
  delay(1000);
  RS485_setup();
  Serial2.begin(57600, SERIAL_8N1,17,13); // for SMT Smart LoRa Board use 13,17
}
void loop()
{
  /*
  RS485_loop();
  datasend2 = String(res_dbl0)+","+String(res_dbl1)+","+String(45.00)+","+String(25.75)+","+String(100.05);
  datasend1 = String(cccode)+","+String(177)+","+String(res_dbl0)+","+String(res_dbl1);
  datasend = datasend1+","+datasend2;
  */
  Heltec.display->clear();
  Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
  Heltec.display->setFont(ArialMT_Plain_10);
  Heltec.display->drawString(0, 0, "Samong IOT Data packet: ");
  Heltec.display->drawString(0, 10, String(counter));
  Heltec.display->drawString(0,20, String(datasend1));
  Heltec.display->drawString(0,30, String(datasend2));
  Heltec.display->display();
  counter=counter+1;
  // send packet
  LoRa.beginPacket();
/*
 * LoRa.setTxPower(txPower,RFOUT_pin);
 * txPower -- 0 ~ 20
 * RFOUT_pin could be RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
 *   - RF_PACONFIG_PASELECT_PABOOST -- LoRa single output via PABOOST, maximum output 20dBm
 *   - RF_PACONFIG_PASELECT_RFO     -- LoRa single output via RFO_HF / RFO_LF, maximum output 14dBm
*/
/*
  LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
  LoRa.print(datasend);
  //LoRa.print(counter);
  LoRa.endPacket();
 */
  RS485_loop1();
  delay(2000);
  /*
  data2 = "22.22";
  data3 = "33.33";
  data4 = "44.44";
  data5 = "55.55";
  data6 = "66.66";
  data7 = "77.77";
   */
  datasend2 = String(data4)+","+String(data5)+","+String(data6)+","+String(data7);
  datasend1 = String(cccode)+","+String(data1)+","+String(data2)+","+String(data3);
  datasend = datasend1+","+datasend2;
  Serial.println(datasend);
  LoRa.setTxPower(14,RF_PACONFIG_PASELECT_PABOOST);
  LoRa.print(datasend);
  //LoRa.print(counter);
  LoRa.endPacket();
  LoRa.print(counter);
  delay(2000);                       // wait for a second
  serial_loop(); // remove comment if to connect serial
}
void RS485_loop1()
{
  long currentMillis = millis();
  if (currentMillis - lastMillis > 1000)
  {
    uint8_t result = modbus.readHoldingRegisters(2,5);  // from 10 will get 2 voltage
    if (getResultMsg(&modbus, result))
    {
      Serial.println();
      res_dbl = modbus.getResponseBuffer(0);
      String res = "Voltage C  : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      data2 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(1);
      res = "Voltage B  : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      data3 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(2);
      res = "Value 23 : " + String(res_dbl) + "  \r\n";
      Serial.println(res);
      data4 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(3);
      res = "Value 24 : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      data5 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(4);
      res = "Value 25 : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      data6 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(5);
      uint32_t value = res_dbl;
      value = value << 16;
      value = value + res_dbl;
      float i = HexTofloat(value);
      res = "Value 26 : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      data7 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(6);
      res = "Power : " + String(res_dbl) + " watt\r\n";
      Serial.println(res);
      data8 = String(res_dbl);
      res_dbl = modbus.getResponseBuffer(7);
      res = "Value 28 : " + String(res_dbl) + " Vac\r\n";
      Serial.println(res);
      //delay(2000);
      data9 = String(res_dbl);
      Serial.print(" Hex to float : ");Serial.println(i);
    }
    lastMillis = currentMillis;
  }
}
bool getResultMsg(ModbusMaster *node, uint16_t result)
{
  String tmpstr2 = "\r\n";
  switch (result)
  {
  case node->ku8MBSuccess:
    return true;
    break;
  case node->ku8MBIllegalFunction:
    tmpstr2 += "Illegal Function";
    break;
  case node->ku8MBIllegalDataAddress:
    tmpstr2 += "Illegal Data Address";
    break;
  case node->ku8MBIllegalDataValue:
    tmpstr2 += "Illegal Data Value";
    break;
  case node->ku8MBSlaveDeviceFailure:
    tmpstr2 += "Slave Device Failure";
    break;
  case node->ku8MBInvalidSlaveID:
    tmpstr2 += "Invalid Slave ID";
    break;
  case node->ku8MBInvalidFunction:
    tmpstr2 += "Invalid Function";
    break;
  case node->ku8MBResponseTimedOut:
    tmpstr2 += "Response Timed Out";
    break;
  case node->ku8MBInvalidCRC:
    tmpstr2 += "Invalid CRC";
    break;
  default:
    tmpstr2 += "Unknown error: " + String(result);
    break;
  }
  Serial.println(tmpstr2);
  return false;
}
void serial_loop()
{
Serial.println("Please wait Serial..");
  while (a == "") {
    Serial2.print("Input1"); //
    a = Serial2.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer1 ");Serial.println(a);
  data3 = String(a);
  delay(1000);
  a="";
  while (a == "") {
    Serial2.print("Input2"); //
    a = Serial2.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer2 ");Serial.println(a);
  data4=String(a);
  a="";
  while (a == "") {
    Serial2.print("Input3"); //
    a = Serial2.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer3 ");Serial.println(a);
  data5=String(a);
  a="";
  while (a == "") {
    Serial2.print("Input4"); //
    a = Serial2.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer4 ");Serial.println(a);
  data6 = String(a);
     a="";
  while (a == "") {
    Serial2.print("Input5"); //
    a = Serial2.readString();  //
    delay(100);
    Serial.print(".");
  }
  Serial.print(" Answer5 ");Serial.println(a);
  data7 = String(a);
}
void Server_loop()
{
}
void ReadServerControl()
{
}