Наскоро се сдобих с панел който измерва напрежение, ток, мощност и енергия – http://www.aliexpress.com/item/PEACEFAIR-AC-100A-Digital-LCD-power-meter-power-energy-Volt-Ammeter-with-shell-4-led-panel/32320321777.html?s=p


Производство е на фирмата Pui Ching (Peacefair), модел PZEM-004 (v3.0). Модулът предлага възможност за включване към компютър (или друг контролер) и възможност за четене на данните от панела в реално време. За комуникация, панела разчита на серийна комуникация от типа RS232 (TTL) с интерфейс който е галванично разделен (чрез оптрони) от мрежовото напрежение.
Поглеждаме отвътре:

Следните по-интересни елементи се забелязват от пръв поглед:
Разбира се, целта бе модулът да се свържи към компютър за да могат данните да се записват някъде. След няколко-дневни, безуспешни опити в комуникация с китайците, да науча детайли относно параметрите на връзката (скорост и др.настройки) реших да поровя в Нет-а и открих, че комуникацията се извършва на 9600, 8-N-1. От китайците, намерих линк от къде може да се изтегли софтуера който предлага възможности да показва индикациите (https://mega.nz/#!WoxGgCSS!A9pDXDXrv8nwUgJmhXBl-dhFt-JzOwuBg_JGq5qsD0o), но за съжаление всичко е на йероглифи и нищо не се разбира.
Следвайки указанията в документацията видях, че трябва да се изпращят заявки (команди) след което модула ще отговори подобаващо. Табличката показва възможните команди и примерни отговори от страна на модула:
NO. |
function |
Head |
Data1- Data5 |
Sum |
1 |
voltage |
B0 |
C0 A8 01 01 00 (Computer sends a request to read the voltage value) |
1A |
A0 |
00 E6 02 00 00 (Meter reply the voltage value is 230.2V) |
88 |
2 |
current |
B1 |
C0 A8 01 01 00 (Computer sends a request to read the current value) |
1B |
A1 |
00 11 20 00 00 (Meter reply the current value is 17.32A) |
D2 |
3 |
Active power |
B2 |
C0 A8 01 01 00 (Computer sends a request to read the active power value) |
1C |
A2 |
08 98 00 00 00 (Meter reply the active power value is 2200w) |
42 |
4 |
Read energy |
B3 |
C0 A8 01 01 00 (Computer sends a request to read the energy value) |
1D |
A3 |
01 86 9f 00 00 (Meter reply the energy value is 99999wh) |
C9 |
5 |
Set the module address |
B4 |
C0 A8 01 01 00 (Computer sends a request to set the address, the address is 192.168.1.1) |
1E |
A4 |
00 00 00 00 00 (Meter reply the address was successfully set) |
A4 |
6 |
Set the power alarm threshold |
B5 |
C0 A8 01 01 14 (computer sends a request to set a power alarm threshold) |
33 |
A5 |
00 00 00 00 00 (Meter reply the power alarm threshold was successfully set) |
A5 |
Или накратко:
B0 C0 A8 01 01 00 1A - sends a request to read the voltage value
B1 C0 A8 01 01 00 1B - sends a request to read the current value
B2 C0 A8 01 01 00 1C - sends a request to read the active power value
B3 C0 A8 01 01 00 1D - sends a request to read the energy value
B4 C0 A8 01 01 00 1E - sends a request to set the address to 192.168.1.1
B5 C0 A8 01 01 14 33 - sends a request to set a power alarm threshold

Остана да се свърже подходящо кабелче към компютъра (USB-RS232/TTL) и да закачите жиците (цветовете може да се различават за различните типове кабели).
За писането на софтуера използвах Borland C++ Builder който е доста стар, но пък удобен за такива малки проекти. След няколко часово експериментиране се получи следната програма с която може да се четат данните:


Частта от кода която обслужва самата комуникация с модула е следната:
HANDLE hComm;
DWORD dwMask;
OVERLAPPED ovr;
DCB dcb;
unsigned char setvalue1[7] = { 0xB4, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x1E }; // Set the address to 192.168.1.1
unsigned char setvalue2[7] = { 0xB0, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x1A }; // Read the voltage value
unsigned char setvalue3[7] = { 0xB1, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x1B }; // Read the current value
unsigned char setvalue4[7] = { 0xB2, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x1C }; // Read the active power value
unsigned char setvalue5[7] = { 0xB3, 0xC0, 0xA8, 0x01, 0x01, 0x00, 0x1D }; // Read the energy value
unsigned char getvalue[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// initialize a serial connection
hComm = CreateFile(ком-порта, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hComm == INVALID_HANDLE_VALUE) { обработка на грешки }
// setup comm params: 9600-8-N-1
GetCommState(hComm, &dcb);
dcb.BaudRate = 9600;
dcb.fOutX = false;
dcb.fInX = false;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(hComm, &dcb);
// Read one char at a time.
GetCommMask(hComm, &dwMask);
dwMask |= EV_RXCHAR;
SetCommMask(hComm, dwMask);
...
//-----------------
// sent query about voltage
for (int i=0; i<7; i++) {
WriteFile(hComm, &setvalue2[i], 1, &dwMask, NULL);
}
Sleep(10);
// read voltage
for (int k=0; k<7; k++) {
ReadFile(hComm, &getvalue[k], 1, &dwMask, NULL);
}
// Display Voltage
Memo1->Lines->Add("Voltage: " + IntToStr(getvalue[2]) + "." + IntToStr(getvalue[3]) + " /V/");
//-----------------
// sent query about Amperage/Current
for (int i=0; i<7; i++) {
WriteFile(hComm, &setvalue3[i], 1, &dwMask, NULL);
}
Sleep(10);
memset(getvalue, 0x0, 7);
// read current
for (int k=0; k<7; k++) {
ReadFile(hComm, &getvalue[k], 1, &dwMask, NULL);
}
// Display Amperage/Current
Memo1->Lines->Add("Current: " + IntToStr(getvalue[2]) + "." + IntToStr(getvalue[3]) + " /A/");
//-----------------
// sent query about active power
for (int i=0; i<7; i++) {
WriteFile(hComm, &setvalue4[i], 1, &dwMask, NULL);
}
Sleep(10);
memset(getvalue, 0x0, 7);
// read active power value
for (int k=0; k<7; k++) {
ReadFile(hComm, &getvalue[k], 1, &dwMask, NULL);
}
// Display Active Power value
Memo1->Lines->Add("Power: " + IntToHex(getvalue[1],2) + " " + IntToHex(getvalue[2],2) + " " + IntToHex(getvalue[3],2) + " /W/");
//-----------------
// sent query about Energy
for (int i=0; i<7; i++) {
WriteFile(hComm, &setvalue5[i], 1, &dwMask, NULL);
}
Sleep(10);
memset(getvalue, 0x0, 7);
// read energy value
for (int k=0; k<7; k++) {
ReadFile(hComm, &getvalue[k], 1, &dwMask, NULL);
}
// Display Energy value
Memo1->Lines->Add("Energy: " + IntToHex(getvalue[1],2) + " " + IntToHex(getvalue[2],2) + " " + IntToHex(getvalue[3],2) + " /Wh/");
//-----------------
CloseHandle(hComm);
Оригиналния китайски софтуер може да бъде изтеглен от тук или тук, като преди това е необходимо да се инсталира драйвер за USB<->RS232 конвертора. Паролата която изисква програмата е admin.
Налична е библиотека за Arduino: https://github.com/olehs/PZEM004T
Подробно ревю на руски има на следния адрес: https://mysku.ru/blog/china-stores/38717.html
Още примери (с Raspberry Pi, Arduino, ESP8266) има на следните линкове:
https://mysku.ru/blog/china-stores/43331.html
https://wiki.cuvoodoo.info/doku.php?id=spark_counter
http://zftlab.org/pages/2016050700.html
http://www.xpablo.cz/?p=899
И накрая, като малка забележка, искам да добавя, че при всяка заявка към модула той издава звук от малък зумер (вижда се на картинката горе) което е доста дразнещо и е по-добре да се разпой от платката.