The spark counter is a custom electricity meter with wireless data logging capability. On one side I have: * a [[#peacefair PZEM-004|peacefair PZEM-004 power meter]] to measure the electricity consumption * a [[#ATmega328P|ATmega328P micro-controller]] to read the measurements out * a [[#nRF24L01+|nRF24L01+ radio]] to transmit the values On the other side: * a [[#nRF24L01+|nRF24L01+ radio]] to receive the values * a [[#Raspberry Pi|Raspberry Pi single board computer]] to store the measurements in an [[https://influxdb.com/|influxDB time series database]] * a [[http://grafana.org/|grafana graphical monitoring tool]] to display the electricity consumption {{:spark_counter:dsc02371.jpg?0x300|complete spark counter}} **warning: the electricity meter I am presenting will only work for 1-phase 2-wire power distribution systems. I have a 3-phase 4-wire system and I was doing it wrong. This has been fixed with the [[spark abacus]].** ====== peacefair PZEM-004 ====== The [[https://www.aliexpress.com/store/1773456|peacefair]] [[https://www.aliexpress.com/store/product/PEACEFAIR-AC-100A-Digital-LCD-power-meter-power-energy-Volt-Ammeter-with-shell-4-led-panel/1773456_32320321777.html|PZEM-004]] is a simple power meter ({{:spark_counter:peacefair_pzem-004_porduct.pdf|datasheet}}). It: * measures voltages 80-260 V AC * measures current 0-100 A AC * calculates the resulting power (W) * records the overall energy consumption (Wh) * displays all these 4 values using 4x7 segments * is powered using 80-260 V AC * provides a TTL UART port to query these values (or set an alarm so to beep when a provided power threshold is reached) {{:spark_counter:dsc02361.jpg?0x200|PZEM-004 front}} {{:spark_counter:dsc02359.jpg?0x200|PZEM-004 back}} The voltage measurement is done over the power input port. The current measurement is done using a coil. Pass the wire on which you would like to measure the current through the coil, and connect the coil to the power meter. A drawing on the back of the device will describe how to connect the wires. {{:spark_counter:dsc02328.jpg?0x200|PZEM-004 opto-couplers}} The meter also provides a UART port (using an XH-4P connector) to query the measured values. Two opto-couplers isolate the main power meter circuits from the TX and RX UART ports. ^ UART ^ PZEM-004 ^ note ^ | 5V | VDD | 3.3V is not enough | | TX | RX | the UART pin needs to be able to sink ~4 mA | | RX | TX | the UART pin needs to be idle high | | GND | GND | | I used a CP2102 based USB to UART converter. CH340 based USB to UART converters will not work (it seems to not be able to sink enough current). And when using the Arduino you should not use the USB port (for serial), since that interferes with the UART signals. The {{:spark_counter:pzem-004.rtf|manual}} provides the corresponding commands, but lacks some information. The UART configurations is 9600 bps 8N1. You have to set the device's address (i.e. C0 A8 01 01 = 192.168.1.1 in the examples) at least once using the 0xB4 command before querying measurements. This address will be saved so the next time (even after power down) you can directly query measurements using the address(es) set in the device(s). All commands include the target device address and only the device with the specified address will respond, except for the command setting the address in the first place. This allows to query multiple devices connected to the same UART port, one after another, when they have different addresses. Note: the optocouplers on the Tx pin of the device have a pull-up resistor. Be sure to remove all but one when using multiple devices, else the low value of the signal will be too high for the receiver to decode the serial communication. The commands use the following 7 bytes message format: - the 1st byte defines the type of command (query/response) and type of content (voltage, current, ...) * the type of command (query/response) is the first nibble * Bx is used for query commands * Ax is used for response commands * type of content (voltage, current, ...) is the second nibble * x0 is used to get the voltage * x1 is used to get the current * x2 is used to get the power * x3 is used to get the energy * x4 is used to set the address * x5 is used to set the power alarm threshold - the next 4 bytes are the address of the device when sending commands, and the measured values in the responses * response values for voltage, current, and power are stored as ''"%u.%u",bytes[1]<<8+bytes[2],bytes[3]'' V/A/W * response values for energy is stored as ''"%lu",bytes[1]<<16+bytes[2]<<8+bytes[3]'' * setting the address or power threshold returns 00 00 00 00 - the 6th byte is used to provide the value of the alarm threshold (in kW), 00 else - the 7th byte is a simple CRC: the sum of all previous bytes Have a look at the manual for examples. Each command triggers a very loud buzzer beep (same a for the alarm). I removed the pizeo-element to prevent this annoying sound. {{:spark_counter:pzem-004-01.jpg?0x200|PZEM-004 board front}} {{:spark_counter:pzem-004-02.jpg?0x200|PZEM-004 board back (without buzzer)}} The power meter uses a single chip solution, the [[http://www.sdicmicro.com/products.html?ic=SD3004|SDIC microelectronics SD3004]] ({{:spark_counter:sd3004_datasheet_v0.2c.pdf|datasheet}}). This chip does all the necessary work: measure voltage and current, drive the 7-segments LED displays, communicate over UART. There is only an additional external I²C EEPROM to store the global energy consumption. ====== ATmega328P ====== {{:spark_counter:dsc02354.jpg?0x200|development board}} {{:spark_counter:dsc02365.jpg?0x200|development setup}} {{ :spark_counter:ic_dev_arduino_nano-30.svg?400|Arduino Nano pinout}} To read out the measurements from the [[#peacefair PZEM-004|power meter]] and send them over [[#nRF24L01+|radio]] I used an [[http://www.atmel.com/devices/atmega328p.aspx|Atmel ATmega328P]] micro-controller. Because the development board costs less than the chip itself I simply used a cheap [[https://www.arduino.cc/en/Main/ArduinoBoardNano|Arduino Nano]] [[http://www.aliexpress.com/wholesale?catId=0&SearchText=arduino+nano|clone]]. USART to query the power meter, SPI to communicate with the nRF24L01+, and the nRF24L01+ protocol are implemented in C (using a lot of interrupts). The source code is available [[https://git.cuvoodoo.info/kingkevin/spark_counter/|in this git]]. I prefer directly writing in the registers as described in the [[http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf|datasheet]] rather than using an [[https://www.arduino.cc/en/Main/Software|abstract IDE]] and [[https://github.com/TMRh20/RF24|libraries]]. This way I learn how it works in details. Arduino - nRF24L01+ connection: ^ ATmega328P signal ^ ATmega328P pin ^ Arduino Nano pin ^ nRF24L01+ board pin ^ nRF24L01+ signal ^ | GND | GND | GND | 1 | GND | | | | 3V (add cap.) | 2 | VCC | | I/O | PB1 | D9 | 3 | CE | | SS | PB2 | D10 | 4 | CSN | | SCK | PB5 | D13 | 5 | SCK | | MOSI | PB3 | D11 | 6 | MOSI | | MISO | PB4 | D12 | 7 | MISO | | INT0 | PD2 | D2 | 8 | IRQ | ====== nRF24L01+ ====== {{:spark_counter:dsc02353.jpg?0x150|nRF24L01+ module}} {{ :spark_counter:nrf24l01_pinout.jpg?250|nRF24L01+ pinout}} To transmit the measurements from the [[#ATmega328P]] to the [[#Raspberry Pi|RPi]] I used [[https://www.nordicsemi.com/eng/Products/2.4GHz-RF/nRF24L01P|nordic nRF24L01+]] RF transceivers. There are very [[http://www.aliexpress.com/wholesale?catId=0&SearchText=nrf24l01|inexpensive]], require low power, provide enough bandwidth for such application, are easy to control, and because I always wanted to try them out. On the [[#ATmega328P|micro-controller]] side I implemented the complete SPI-based protocol using the [[https://www.nordicsemi.com/eng/content/download/2726/34069/file/nRF24L01P_Product_Specification_1_0.pdf|datasheet]]. The source code is available [[https://git.cuvoodoo.info/kingkevin/spark_counter/|in this git]]. On the [[#Raspberry Pi|computer]] side I use the [[https://github.com/TMRh20/RF24|RF24 library]]. The [[https://tmrh20.github.io/RF24/RPi.html|documentation]] is straight forward and saved me some time re-implementing the protocol a second time. ====== Raspberry Pi ====== {{:spark_counter:dsc02375.jpg?0x200|RPi setup}} {{ :spark_counter:pi-gpio-header-26-sm.png?200|RPi P1 header}} To store the measurements I use a [[https://www.raspberrypi.org/products/model-b/|Raspberry Pi Model B1]] ([[http://elinux.org/RPi_HardwareHistory|rev 0002]]). It's a tiny single board computer which was laying around for quite some time now. To receive the measurements I used a [[#nRF24L01+|nRF24L01+ transceiver]] with the [[https://github.com/TMRh20/RF24|RF24 library]]. The source code is available [[https://git.cuvoodoo.info/kingkevin/spark_counter/|in this git]]. [[http://elinux.org/RPi_Low-level_peripherals#P1_Header|RPi]] - nRF24L01+ connection: ^ RPi signal ^ RPi pin ^ nRF24L01+ board pin ^ nRF24L01+ signal ^ | GND | P1_20 | 1 | GND | | +3V3 | P1_17 | 2 | VCC | | GPIO25 | P1_22 | 3 | CE | | GPIO8/CE0# | P1_24 | 4 | CSN | | GPIO11/SCLK | P1_23 | 5 | SCK | | GPIO10/MOSI | P1_19 | 6 | MOSI | | GPIO9/MISO | P1_21 | 7 | MISO | | GPIO24 | P1_18 | 8 | IRQ | The values are then simply stored in an [[https://influxdb.com/|InfluxDB]] time series database for visualisation in [[http://grafana.org/|grafana]]. Note: there is no ARM build of grafana (armel for RPi 1, armhf for later versions). This is also because there is no ARM release of [[http://phantomjs.org/|PhantomJS]]. I'm running grafana on my local computer (amd64), using the remote database on the RPi. {{:spark_counter:grafana.png?0x200|grafana visualization}}