// YIGE Digital Power Meter (Model : YG889E-3SY) Online Monitoring using Blynk App By Solarduino // Note Summary // Note : Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk. // Note : This DPM Monitoring Code specifically for DPM YIGE YG889E-3SY to measure values for communication and display. // Note : You as a buyer should request the seller to provide the User Manual in order to determine the communication or register address (sometimes manufacturer may revise or update their register address) // Note : This Code monitors AC Voltage, current, Power, Energy and other parameters that shown in the Manual (kindly refer to Manufacturer latest Manual) // Note : The values are directly taken from DPM and function of Node MCU is only to read the value and for further submission to Blynk Server for display. // Note : You need to download and install (modified) Modbus Master library at our website (https://solarduino.com/pzem-014-or-016-ac-energy-meter-with-arduino/ ) // Note : You need to download the Blynk App on your smart phone for display. // Note : Blog page for this code : https://solarduino.com/online-monitoring-for-digital-power-meter-model-yg889e-3sy-through-modbus-rtu-rs485-using-blynk-and-nodemcu/ /*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/ /* Virtual Serial Port */ #include /* include virtual Serial Port coding */ SoftwareSerial DPMSerial; // Move the YiGe DPM communication pins from Rx to pin D1 = GPIO 5 & TX to pin D2 = GPIO 4 /* 0- Blynk Server and Wifi Connection */ #include // Enable the use of wifi module. Make sure you downloaded and installed the ESP8266 library #include char auth[] = "c_hwJP2R9CIFOYz71OAlpyCHVMWv_OFh"; // Put in the Auth Token for the project from Blynk. You should receive it in your email. char ssid[] = "KS LIM-FIBRE"; // Key in your wifi name. You can check with your smart phone for your wifi name char pass[] = "58828515"; // Key in your wifi password. /* 1- Modbus & RS485 Converter*/ #include // Load the (modified) library for modbus communication command codes. Kindly install at our website. #define MAX485_DE 16 // Define DE Pin to Arduino pin. Connect DE Pin of Max485 converter module to Pin D0 (GPIO 16) Node MCU board #define MAX485_RE 5 // Define RE Pin to Arduino pin. Connect RE Pin of Max485 converter module to Pin D1 (GIPO 5) Node MCU board // These DE anr RE pins can be any other Digital Pins to be activated during transmission and reception process. static uint8_t DPMAddr = 0x01; // Declare the address of device (meter 1) in term of 8 bits. ModbusMaster node; /* activate modbus master codes*/ /* 2 - Digital Power Meter (DPM)*/ int DisplayBrightness =0; /* Declare variable for LED Display (0 to 9) */ int Address =0; /* Declare variable for DPM Slave Address ( 0 to 247) */ int BaudRate =0; /* Declare variable for Baud Rate (0 = 9600; 1 = 4800; 2 =2400) */ int VSelect =0; /* Declare variable for Voltage Selection (0 = 400Vac, 1 = 100Vac if using PT) */ int ISelect =0; /* Declare variable for Current Selection (0 = 5A; 1 = 1A for secondary transformer ratio) */ int Network =0; /* Declare variable for Network Selection (0 = 3 Live 3 Wires; 1 = 3 Live 4 Wires include Neutral) */ int PTRatio =0; /* Declare variable for Potentio Transformer Ratio (value 10 = 1 ratio) */ int CTRatio =0; /* Declare variable for Current Transformer Ratio (value 10 = 10 ratio) */ int Status =0; /* Reserve for future use */ float Ua =0; float Ub =0; float Uc =0; /* Declare variable for 1st, 2nd, 3rd Phase AC Voltage (phase to Neutral)*/ float Uab =0; float Ubc =0; float Uca =0; /* Declare variable for phase to phase voltage (1st & 2nd, 2nd & 3rd, 3rd & 1st phase)*/ float Ia =0; float Ib =0; float Ic =0; float It =0; /* Declare variable for 1st, 2nd, 3rd Phase & total average AC Current*/ float Pa =0; float Pb =0; float Pc =0; float Pt =0; /* Declare variable for 1st, 2nd, 3rd Phase & total Real Power (W)*/ float Qa =0; float Qb =0; float Qc =0; float Qt =0; /* Declare variable for 1st, 2nd, 3rd Phase & total Reactive Power (Var)*/ float Sa =0; float Sb =0; float Sc =0; float St =0; /* Declare variable for 1st, 2nd, 3rd Phase & total Apparent Power (VA)*/ float Pfa =0; float Pfb =0; float Pfc =0; float Pft =0; /* Declare variable for 1st, 2nd, 3rd Phase & total average Power Factor (Pf))*/ float Hz =0; /* Declare variable for frequency (Hz))*/ float pkWh =0; float nkWh =0; /* Declare variable for positive & negative Real Energy (kWh)*/ float pkVarh =0; float nkVarh =0; /* Declare variable for positive & negative Reactive Energy (kVarh)*/ /* 3 - Counting Time */ unsigned long startMillisDPM; /* start counting time for Display */ unsigned long currentMillisDPM; /* current counting time for Display */ const unsigned long periodDPM = 1000; // refresh every X seconds (in seconds) for Display. Default 1000 = 1 second /* 2 - Data submission to Blynk Server */ unsigned long startMillisReadData; /* start counting time for data collection */ unsigned long currentMillisReadData; /* current counting time for data collection */ const unsigned long periodReadData = 5000; /* refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second */ void setup() { /*0 General*/ startMillisDPM = millis(); /* Start counting time*/ Serial.begin(9600); /* To assign communication port to communicate between NodeMCU & PC*/ DPMSerial.begin(9600,SWSERIAL_8N2,4,0); /* Create a virtual communication port to communicate between NodeMCU & DPM */ // 4 = Rx/R0 of RS485 converter to GPIO 4 (pin D2 of NodeMCU) & 0 = Tx/DI of RS485 converter to GPIO 0 (pin D3 of NodeMCU) on NodeMCU Blynk.begin(auth,ssid,pass); /* 1- Modbus & RS485 Converter*/ pinMode(MAX485_RE, OUTPUT); /* Define RE Pin as Signal Output for RS485 converter. Output pin means Arduino command the pin signal to go high or low so that signal is received by the converter*/ pinMode(MAX485_DE, OUTPUT); /* Define DE Pin as Signal Output for RS485 converter. Output pin means Arduino command the pin signal to go high or low so that signal is received by the converter*/ digitalWrite(MAX485_RE, 0); /* Arduino create output signal for pin RE as LOW (no output)*/ digitalWrite(MAX485_DE, 0); /* Arduino create output signal for pin DE as LOW (no output)*/ // both pins no output means the converter is in communication signal receiving mode node.preTransmission(preTransmission); // Callbacks allow us to configure the RS485 transceiver correctly node.postTransmission(postTransmission); node.begin(DPMAddr,DPMSerial); /* Initialize Modbus with correct DPM address & virtual serial port to DPM*/ delay(1000); /* after everything done, wait for 1 second */ /* 1 - Digital Power Meter (DPM)*/ uint16_t result; /* Declare variable "result" as 8 bits */ result = node.readHoldingRegisters(0x0000, 97); /* If all 97 Registers (starting 0x0000 to 0x0097 registers)are responsive, run the codes below*/ if (result == node.ku8MBSuccess) /* If there is a response */ { DisplayBrightness = node.getResponseBuffer(0x0000) ; Address = node.getResponseBuffer(0x0001) ; BaudRate = node.getResponseBuffer(0x0002) ; VSelect = node.getResponseBuffer(0x0003) ; ISelect = node.getResponseBuffer(0x0004) ; Network = node.getResponseBuffer(0x0005) ; PTRatio = node.getResponseBuffer(0x0006) ; CTRatio = node.getResponseBuffer(0x0007) ; Serial.print("YiGE DPM LCD Brightness (0-9) : "); Serial.println(DisplayBrightness); Serial.print("YiGE DPM Address (0-247) : "); Serial.println(Address); Serial.print("YiGE DPM Baud Rate (0=9600;1=4800;2=2400): "); Serial.println(BaudRate); Serial.print("YiGE DPM Voltage Mode (0=400V; 1=100V) : "); Serial.println(VSelect); Serial.print("YiGE DPM Current Mode (0=5A; 1=1A : "); Serial.println(ISelect); Serial.print("YiGE DPM Network Mode (0=3 Phase 3 Wire; 1=3 Phase 4 Wires) : "); Serial.println(Network); Serial.print("YiGE DPM PT Ratio (10= 1 ratio): "); Serial.println(PTRatio); Serial.print("YiGE DPM CT Ratio (1= 1 ratio): "); Serial.println(CTRatio); } /* 2 - Data submission to Blynk Server */ startMillisReadData = millis(); /* Start counting time for data submission to Blynk Server*/ } void loop() { /* 0- General */ Blynk.run(); /* 1 - Digital Power Meter (DPM)*/ currentMillisDPM = millis(); /* Record current time*/ if (currentMillisDPM - startMillisDPM >= periodDPM) /* for every x seconds, run the codes below*/ { uint16_t result; /* Declare variable "result" as 8 bits */ result = node.readHoldingRegisters(0x0000, 97); /* If all 97 Registers (starting 0x0000 to 0x0097 registers)are responsive, run the codes below*/ if (result == node.ku8MBSuccess) /* If there is a response */ { // Merge 2 x 16 bits or 2 register addresses into 1 float value (refer to manual) union { uint32_t x; float f;} u; // These codes required to merge 2 x 16 bits (2 register addresses into 1 float number float z = u.f; Serial.println("Voltage (V) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(9) << 16) | node.getResponseBuffer(10); z = u.f; Ua = z; Serial.print(Ua); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(11) << 16) | node.getResponseBuffer(12); z = u.f; Ub = z; Serial.print(Ub); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(13) << 16) | node.getResponseBuffer(14); z = u.f; Uc = z; Serial.print(Uc); Serial.println("");Serial.println(""); // Voltage phase to phase not working properly /* Serial.println("Voltage (V) phase to phase :"); u.x = ((unsigned long)node.getResponseBuffer(65) << 16) | node.getResponseBuffer(66); z = u.f; Ubc = z; Serial.print(Ubc); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(67) << 16) | node.getResponseBuffer(68); z = u.f; Ubc = z; Serial.print(Ubc); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(69) << 16) | node.getResponseBuffer(70); z = u.f; Uca = z; Serial.print(Uca); Serial.println("");Serial.println(""); */ Serial.println("Current (I) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(15) << 16) | node.getResponseBuffer(16); z = u.f; Ia = z; Serial.print(Ia,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(17) << 16) | node.getResponseBuffer(18); z = u.f; Ib = z; Serial.print(Ib,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(19) << 16) | node.getResponseBuffer(20); z = u.f; Ic = z; Serial.print(Ic,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(21) << 16) | node.getResponseBuffer(22); z = u.f; It = z; Serial.print("Net: "); Serial.println(It,5);Serial.println(""); Serial.println("Real Power (W) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(39) << 16) | node.getResponseBuffer(40); z = u.f; Pa = z; Serial.print(Pa); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(41) << 16) | node.getResponseBuffer(42); z = u.f; Pb = z; Serial.print(Pb); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(43) << 16) | node.getResponseBuffer(44); z = u.f; Pc = z; Serial.print(Pc); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(23) << 16) | node.getResponseBuffer(24); z = u.f; Pt = z; Serial.print("Net: "); Serial.println(Pt);Serial.println(""); Serial.println("Reactive Power (Var) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(45) << 16) | node.getResponseBuffer(46); z = u.f; Qa = z; Serial.print(Qa); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(47) << 16) | node.getResponseBuffer(48); z = u.f; Qb = z; Serial.print(Qb); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(49) << 16) | node.getResponseBuffer(50); z = u.f; Qc = z; Serial.print(Qc); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(25) << 16) | node.getResponseBuffer(26); z = u.f; Qt = z; Serial.print("Net: "); Serial.println(Qt);Serial.println(""); Serial.println("Apparent Power (VA) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(51) << 16) | node.getResponseBuffer(52); z = u.f; Sa = z; Serial.print(Sa); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(53) << 16) | node.getResponseBuffer(54); z = u.f; Sb = z; Serial.print(Sb); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(55) << 16) | node.getResponseBuffer(56); z = u.f; Sc = z; Serial.print(Sc); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(57) << 16) | node.getResponseBuffer(58); z = u.f; St = z; Serial.print("Net: "); Serial.println(St);Serial.println(""); Serial.println("Power Factor (Pf) per phase :"); u.x = ((unsigned long)node.getResponseBuffer(59) << 16) | node.getResponseBuffer(60); z = u.f; Pfa = z; Serial.print(Pfa,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(61) << 16) | node.getResponseBuffer(62); z = u.f; Pfb = z; Serial.print(Pfb,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(63) << 16) | node.getResponseBuffer(64); z = u.f; Pfc = z; Serial.print(Pfc,5); Serial.print(" ; "); u.x = ((unsigned long)node.getResponseBuffer(27) << 16) | node.getResponseBuffer(28); z = u.f; Pft = z; Serial.print("Net: "); Serial.println(Pft,5);Serial.println(""); Serial.println("Frequency (Hz) :"); u.x = ((unsigned long)node.getResponseBuffer(29) << 16) | node.getResponseBuffer(30); z = u.f; Hz = z; Serial.println(Hz); Serial.print(" ; "); Serial.println(""); Serial.println("Real Power Energy (With Direction) :"); u.x = ((unsigned long)node.getResponseBuffer(31) << 16) | node.getResponseBuffer(32); z = u.f; pkWh = z; Serial.print(pkWh);Serial.print(" (+) ; "); u.x = ((unsigned long)node.getResponseBuffer(33) << 16) | node.getResponseBuffer(34); z = u.f; nkWh = z; Serial.print(nkWh);Serial.println(" (-) ; "); Serial.println(""); // Codes not working properly /* Serial.println("Real Power Energy (With Direction)2 :"); u.x = ((unsigned long)node.getResponseBuffer(71) << 16) | node.getResponseBuffer(72); z = u.f; pkWh = z; Serial.print(pkWh);Serial.print(" (+) ; "); u.x = ((unsigned long)node.getResponseBuffer(73) << 16) | node.getResponseBuffer(74); z = u.f; nkWh = z; Serial.print(nkWh);Serial.println(" (-) ; "); */ Serial.println("Reactive Power Energy (With Direction) :"); u.x = ((unsigned long)node.getResponseBuffer(35) << 16) | node.getResponseBuffer(36); z = u.f; pkVarh = z; Serial.print(pkVarh);Serial.print(" (+) ; "); u.x = ((unsigned long)node.getResponseBuffer(37) << 16) | node.getResponseBuffer(38); z = u.f; nkVarh = z; Serial.print(nkVarh);Serial.println(" (-) ; "); Serial.println(""); // Codes not working properly /*Serial.println("Reactive Power Energy (With Direction)2 :"); u.x = ((unsigned long)node.getResponseBuffer(75) << 16) | node.getResponseBuffer(76); z = u.f; pkVarh = z; Serial.print(pkVarh);Serial.print(" (+) ; "); u.x = ((unsigned long)node.getResponseBuffer(77) << 16) | node.getResponseBuffer(78); z = u.f; nkVarh = z; Serial.print(nkVarh);Serial.println(" (-) ; "); */ if (DPMAddr==2) /* just for checking purpose to see whether can read modbus*/ { } } else { } startMillisDPM = currentMillisDPM ; /* Set the starting point again for next counting time */ } /* count time for program run every second (by default)*/ /* 2 - Data submission to Blynk Server */ currentMillisReadData = millis(); /* Set counting time for data submission to server*/ if (currentMillisReadData - startMillisReadData >= periodReadData) /* for every x seconds, run the codes below*/ { Blynk.virtualWrite(V0,Ua); // Send data to Blynk Server. Blynk.virtualWrite(V1,Ub); Blynk.virtualWrite(V2,Uc); Blynk.virtualWrite(V3,Ia); Blynk.virtualWrite(V4,Ib); Blynk.virtualWrite(V5,Ic); Blynk.virtualWrite(V6,It); Blynk.virtualWrite(V7,Pa); Blynk.virtualWrite(V8,Pb); Blynk.virtualWrite(V9,Pc); Blynk.virtualWrite(V10,Pt); Blynk.virtualWrite(V11,Qa); Blynk.virtualWrite(V12,Qb); Blynk.virtualWrite(V13,Qc); Blynk.virtualWrite(V14,Qt); Blynk.virtualWrite(V15,Sa); Blynk.virtualWrite(V16,Sb); Blynk.virtualWrite(V17,Sc); Blynk.virtualWrite(V18,St); Blynk.virtualWrite(V19,Pfa); Blynk.virtualWrite(V20,Pfb); Blynk.virtualWrite(V21,Pfc); Blynk.virtualWrite(V22,Pft); Blynk.virtualWrite(V23,Hz); Blynk.virtualWrite(V24,pkWh); Blynk.virtualWrite(V25,nkWh); Blynk.virtualWrite(V26,pkVarh); Blynk.virtualWrite(V27,nkVarh); startMillisReadData = millis(); } } void preTransmission() /* transmission program when triggered*/ { /* 1- PZEM-017 DC Energy Meter */ digitalWrite(MAX485_RE, 1); /* put RE Pin to high*/ digitalWrite(MAX485_DE, 1); /* put DE Pin to high*/ delay(1); // When both RE and DE Pin are high, converter is allow to transmit communication } void postTransmission() /* Reception program when triggered*/ { /* 1- PZEM-017 DC Energy Meter */ delay(3); // When both RE and DE Pin are low, converter is allow to receive communication digitalWrite(MAX485_RE, 0); /* put RE Pin to low*/ digitalWrite(MAX485_DE, 0); /* put DE Pin to low*/ }