diff --git a/lib/sensor_pzem.c b/lib/sensor_pzem.c
new file mode 100644
index 0000000..5780cac
--- /dev/null
+++ b/lib/sensor_pzem.c
@@ -0,0 +1,166 @@
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+/** library to query measurements from peacefair PZEM-004 and PZEM-004T electricity meter (code)
+ * @file sensor_pzem.c
+ * @author King Kévin
+ * @date 2016
+ * @note peripherals used: USART @ref sensor_pzem_usart
+ */
+
+/* standard libraries */
+#include // standard integer types
+#include // general utilities
+
+/* STM32 (including CM3) libraries */
+#include // real-time control clock library
+#include // general purpose input output library
+#include // universal synchronous asynchronous receiver transmitter library
+#include // interrupt handler
+#include // Cortex M3 utilities
+
+#include "sensor_pzem.h" // PZEM electricity meter header and definitions
+#include "global.h" // common methods
+
+/** @defgroup sensor_pzem_usart USART peripheral used for communication with electricity meter
+ * @{
+ */
+#define SENSOR_PZEM_USART 2 /**< USART peripheral */
+/** @} */
+
+#define USART_BAUDRATE 115200 /**< serial baudrate, in bits per second (with 8N1 8 bits, no parity bit, 1 stop bit settings) */
+
+/* input and output ring buffer, indexes, and available memory */
+static uint8_t rx_buffer[7] = {0}; /**< buffer for received response */
+static volatile uint8_t rx_i = 0; /**< current position of read received data */
+static uint8_t tx_buffer[7] = {0}; /**< buffer for request to transmit */
+static volatile uint8_t tx_i = 0; /**< current position if transmitted data */
+
+volatile bool sensor_pzem_measurement_received = false;
+
+void sensor_pzem_setup(void)
+{
+ /* enable USART I/O peripheral */
+ rcc_periph_clock_enable(USART_PORT_RCC(SENSOR_PZEM_USART)); // enable clock for USART port peripheral
+ rcc_periph_clock_enable(USART_RCC(SENSOR_PZEM_USART)); // enable clock for USART peripheral
+ gpio_set_mode(USART_PORT(SENSOR_PZEM_USART), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_PIN_TX(SENSOR_PZEM_USART)); // setup GPIO pin USART transmit
+ gpio_set_mode(USART_PORT(SENSOR_PZEM_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, USART_PIN_RX(SENSOR_PZEM_USART)); // setup GPIO pin USART receive
+ gpio_set(USART_PORT(SENSOR_PZEM_USART), USART_PIN_RX(SENSOR_PZEM_USART)); // pull up to avoid noise when not connected
+
+ /* setup USART parameters for electricity meter: 9600 8N1 */
+ usart_set_baudrate(USART(SENSOR_PZEM_USART), 9600); // the electricity meter uses a fixed baud rate of 9600 bps
+ usart_set_databits(USART(SENSOR_PZEM_USART), 8);
+ usart_set_stopbits(USART(SENSOR_PZEM_USART), USART_STOPBITS_1);
+ usart_set_mode(USART(SENSOR_PZEM_USART), USART_MODE_TX_RX);
+ usart_set_parity(USART(SENSOR_PZEM_USART), USART_PARITY_NONE);
+ usart_set_flow_control(USART(SENSOR_PZEM_USART), USART_FLOWCONTROL_NONE);
+
+ nvic_enable_irq(USART_IRQ(SENSOR_PZEM_USART)); // enable the USART interrupt
+ usart_enable_rx_interrupt(USART(SENSOR_PZEM_USART)); // enable receive interrupt
+ usart_enable(USART(SENSOR_PZEM_USART)); // enable USART
+
+ /* reset buffer states */
+ tx_i = 0;
+ rx_i = 0;
+ sensor_pzem_measurement_received = false;
+}
+
+void sensor_pzem_measurement_request(uint32_t address, enum sensor_pzem_measurement_type_t type)
+{
+ if (tx_i!=0) { // transmission is ongoing
+ return;
+ }
+ if (type>=MAX) { // invalid type
+ return;
+ }
+ tx_buffer[0] = 0xB0+type; // set request nibble and type nibble
+ tx_buffer[1] = (address>>24)&0xff; // set address
+ tx_buffer[2] = (address>>16)&0xff; // set address
+ tx_buffer[3] = (address>>8)&0xff; // set address
+ tx_buffer[4] = (address>>0)&0xff; // set address
+ tx_buffer[5] = 0; // only used to set alarm
+ tx_buffer[6] = 0; // to calculate checksum (sum of all previous bytes)
+ for (uint8_t i=0; i=MAX) { // not a valid response type received (actually 4 and 5 are valid, but should not happen when using this code
+ return measurement;
+ }
+ uint8_t checksum = 0; // calculate checksum (sum of all other bytes)
+ for (uint8_t i=0; i=LENGTH(rx_buffer)) { // buffer full
+ sensor_pzem_measurement_received = true; // notify used response has been received
+ }
+ } else { // previous response not read before receiving the next
+ usart_recv(USART(SENSOR_PZEM_USART)); // drop received buffer
+ }
+ }
+}
diff --git a/lib/sensor_pzem.h b/lib/sensor_pzem.h
new file mode 100644
index 0000000..de41a62
--- /dev/null
+++ b/lib/sensor_pzem.h
@@ -0,0 +1,57 @@
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+/** library to query measurements from peacefair PZEM-004 and PZEM-004T electricity meter (API)
+ * @file sensor_pzem.h
+ * @author King Kévin
+ * @date 2016
+ * @note peripherals used: USART @ref sensor_pzem_usart
+ */
+#pragma once
+
+/** a measurement response has been received */
+extern volatile bool sensor_pzem_measurement_received;
+
+/** measurements offered by energy meter */
+enum sensor_pzem_measurement_type_t {
+ VOLTAGE = 0,
+ CURRENT = 1,
+ POWER = 2,
+ ENERGY = 3,
+ MAX
+};
+
+/** measurement returned by energy meter */
+struct sensor_pzem_measurement_t {
+ enum sensor_pzem_measurement_type_t type; /**< measurement type */
+ bool valid; /**< is the measurement valid (e.g. format and checksum are correct) */
+ union measurement_t { /**< measurement value */
+ float voltage; /**< measured voltage in volts */
+ float current; /**< measured current in amperes */
+ float power; /**< measured power in watts */
+ uint32_t energy; /**< measured energy in watts/hour (24 bits) */
+ } value;
+};
+
+/** setup peripherals to communicate with electricity meter */
+void sensor_pzem_setup(void);
+/** request measurement from electricity meter
+ * @param[in] address electricity meter device address
+ * @param[in] sensor_pzem_measurement_type measurement type to request
+ */
+void sensor_pzem_measurement_request(uint32_t address, enum sensor_pzem_measurement_type_t type);
+/** decode received measurement
+ * @return decoded measurement (invalid if no new measurement has been received)
+ */
+struct sensor_pzem_measurement_t sensor_pzem_measurement_decode(void);