Monitor Your Energy Bill with Modbus and the Arduino Cloud
Connect a Modbus energy meter to an Arduino® MKR WiFi 1010 board and a MKR 485 Shield and monitor the power consumption of your home via an Arduino Cloud IoT dashboard.
Introduction
If you really want to make your home smarter, you'll probably want start from your monthly bills (for example, energy, gas, etc...). As some say: good for the planet, the wallet and the bottom line. In this tutorial, we are going to learn how to connect a Modbus energy meter to the Arduino Cloud IoT using an Arduino® MKR WiFi 1010 board and an Arduino® MKR 485 Shield.
This tutorial assumes you know the basics of the Arduino Cloud. If you are new check out our Getting Started Guide.
Goals
The goals with this tutorial are:
- Learn how to connect a Modbus energy meter to the Arduino Cloud IoT.
- Learn how to use the Arduino® MKR 485 Shield with an Arduino® MKR WiFi 1010 board.
Hardware and Software Needed
The hardware and software used in this tutorial:
- Arduino Cloud IoT.
- Arduino Create Agent.
- Arduino Modbus library
- Arduino® MKR WiFi 1010 board.
- Arduino® MKR 485 Shield.
- Finder Type 7E.64 Energy Meter.
- Twisted single pair shielded cable.
- Micro USB cable.
Electric Meters a.k.a Energy Meters
Energy consumption awareness is a key factor to reduce energy costs and improve energy efficiency; we can measure energy consuption using electric meters, a.k.a energy meters.
Electric meters, also known as energy meters, are electronic devices that can measure the amount of energy consumed by an electrically powered equipment such as a refrigerator or a lamp. Energy meters can be use also to measure the energy consuption of houses and buildings. While different types of energy meters exist, in this tutorial we choose a Finder Type 7E.64 Energy Meter. This energy meter is designed for DIN rail use and fits perfectly in the main cabinet of our house. Also, this energy meter has a RS-485 Modbus interface, this is an industrial communication protocol that can be decoded in Arduino boards using an Arduino MKR 485 Shield and the Arduino Modbus library.
Setting Up the Finder Type 7E.64 Energy Meter
First, you must install the energy meter in your electrical cabinet. To ensure you are working in a safe environment, turn off the power from the electrical terminal ahead of your system and double check with a multimeter that there is no voltage between the terminals.
Warning! Check your country regulations about dealing with your house electrical system and be extremely careful because it can be deadly! If you don't know how, call an electrician.
Place the energy meter inside your cabinet and connect the live and neutral wires from the main breaker to the input of the meter, remember to use the standard color convention (blue for neutral and brown/black/grey for live in EU. The output has to be connected to the rest of the system.
Now it is time make the connection between the energy meter and our MKR WiFi 1010 board! For this, we will use twisted single pair cable with ground. This type of cable is typically used for phone lines, so it can be used to transmit electrical signals over long distances (up to 1.2 km). However, we are going to use a cable long enough to exit the cabinet and place our MKR WiFi 1010 board in an accessible place.
The RS-485 standard names its terminals A, B and COM. A common de-facto standard is the use of TX+/RX+ (or D+) as an alternative for B (high for mark i.e. idle) and TX-/RX- (or D-) as an alternative for A (low for mark i.e. idle). As shown in the image above, we connected the red cable to the D+ terminal, the white cable to the D- terminal and the brown cable to the COM terminal of the energy meter. You can read more about the RS-485 standard here.
The Finder energy meter supports half-duplex communication, this means that data can move in two directions, but not at the same time. The MKR 485 Shield supports both half and full-duplex communication (this means data moving in two directions simultaneously), so we need to set up the shield for half-duplex communication. In the MKR 485 Shield, half-duplex communication uses Y and Z terminals, Y terminal is B or D+ and Z terminal y A or D-, this means that the red cable must be connected to Y terminal and the white cable to Z terminal; the brown cable (COM) must be connected to ISOGND terminal. Also, we need to set the second switch to HALF (2 to OFF) and the third switch to Y-Z (3 to ON): the first switch is not used in half-duplex communication. The third switch is used for setting up the termination, this is a resistor connecting the two data terminals that is used for dampening interferences. The complete shield setup is shown in the image below:
Now, we can connect the MKR 485 Shield and the MKR WiFi 1010 board:
Now that we have finished setting up the hardware, it is time to connect our energy meter to the Arduino Cloud IoT
Setting Up the Arduino Cloud IoT
- Create a Thing with the following variables:
Variable | Type | Permission | Update Policy |
---|---|---|---|
voltage | Floating Point Number | Read Only | On change |
current | Floating Point Number | Read Only | On change |
power | Floating Point Number | Read Only | On change |
frequency | Floating Point Number | Read Only | On change |
energy | Floating Point Number | Read Only | On change |
- Set up your MKR WiFi 1010 and configure your network credentials.
Creating a Sketch for a "Thing" in the Arduino Cloud IoT
Once we are finished with all the configurations of the "Energy Thing", we can move on to creating the sketch that we are going to upload to our MKR WiFi 1010 board. To do so, we first need to go to the "Sketch" tab. But before, let's talk about Modbus.
Modbus is an open source communication protocol designed specifically for industrial sensors and machines. In simple terms, it is a method used for transmitting information over serial lines between electronic devices. Our MKR WiFi 1010 board can talk Modbus using the Arduino Modbus library. This library packs all the handlers and makes hooking up any Modbus device to some of the Arduino® boards (like the MKR family boards) really fast and easy. You can read more about Modbus here.
In the datasheet of the energy meter we can find all the Modbus related information we need like its function codes, address of its registers and also their sizes.
Modbus messages follow a simple structure, for example:
01 03 04 00 16 00 02 25 C7
In this structure:
is the device address.0x01
is the function code that tells the Modbus device if we want to read or write data. In this tutorial, we want to read data from the holding registers of the energy meter.0x03
for byte count, this specifies how may data items are being returned.0x04
is register address from the Modbus device we want to read.00 16
is the size of the register in words (every word is 2 bytes long).00 02
is a CRC code. This code is generated from a math function over previous bytes, it ensures that the message has been received correctly.25 C7
The Arduino Modbus library handles this structure. For example, for reading the register of the energy meter that holds information about current, we have the following function that uses the
requestFrom()
function of the Arduino Modbus library:1/* 2Function readCurrent()3Description: read current value from the Finder energy meter holding registers4
5Created by Alberto Perro (Officine Innesto)6Modified by José Bagur7*/8
9float readCurrent() { 10 float ampere = 0.;11 // Send reading request over RS485 12 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x0016, 2)) {13 // Error handling 14 Serial.print("- Failed to read the current! "); 15 Serial.println(ModbusRTUClient.lastError()); 16 } else { 17 // Response handler 18 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer19 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer20 int32_t milliamp = word1 << 16 | word2; // Join word1 and word2 to retrieve current value in milliampere21 ampere = milliamp/1000.0; // Convert current to ampere22 } 23return ampere;24}
In the
else
we have the response handler. Since this register is two words long, we have to join them with binary math. We read the words from the buffer and store them in an unsigned 16-bit integer (2 bytes or a word); then we join them in a signed 32-bit integer by bitshifting the first word to the left and apply an OR over the second word. The result is the current measurement in milliampere (in ampere after dividing it by 1000). This process can adapted to everything else we want to read from the energy meter: voltage, power, frequency and energy.The complete sketch we are going to upload to out MKR WiFi 1010 board can be found below, notice that the Arduino Cloud IoT generated automatically the code that is dedicated to handling Internet connectivity:
1/* -----------------------------------------2 * Finder Energy Meter to Arduino Cloud IoT3 * -----------------------------------------4 * This sketch provides a full bridge between the Finder energy meter and the 5 * Arduino Cloud IoT. This sketch was developed to monitor electricity costs 6 * and usage in Casa Jasmina.7 *8 * Created by Alberto Perro (Officine Innesto)9 * Modified by José Bagur10*/11 12#include <ArduinoRS485.h>13#include <ArduinoModbus.h>14
15#undef ON16#undef OFF17
18#include "thingProperties.h"19
20unsigned long rate = 60000; // Default refresh rate in ms21unsigned long lastMillis = 0;22
23void setup() {24 // Initialize serial port at 9600 bauds and wait for it to open25 Serial.begin(9600);26 delay(1500); 27
28 // Defined in thingProperties.h29 initProperties();30
31 // Connect to Arduino Cloud IoT32 ArduinoCloud.begin(ArduinoIoTPreferredConnection);33 34 /*35 The following function allows you to obtain more information36 related to the state of network and Cloud IoT connection and errors37 The higher number the more granular information you’ll get38 The default value is 0 (only errors)39 Maximum is 440 */41 setDebugMessageLevel(2);42 ArduinoCloud.printDebugInfo();43 44 // Start Modbus RTU client45 if (!ModbusRTUClient.begin(9600)) {46 Serial.println("- Failed to start Modbus RTU Client!");47 while (1);48 }49}50
51void loop() {52 // Update "Energy Thing" variables connected to Arduino Cloud IoT53 ArduinoCloud.update();54 55 // Update energy meter data and show it via the Serial Monitor56 if (millis() - lastMillis > rate) {57 lastMillis = millis();58 59 voltage = readVoltage();60 delay(100);61 current = readCurrent();62 delay(100);63 power = readPower();64 delay(100);65 frequency = readFreq();66 delay(100);67 energy = readEnergy();68 69 Serial.print("- " + String(voltage, 3) + "V " + String(current, 3) + "A " + String(power, 3) + "W ");70 Serial.println(String(frequency, 3) + "Hz " + String(power, 3) + "kWh");71 delay(100);72 } 73}74
75/* Functions to read Finder energy meter holding registers76 * For more information: https://gfinder.findernet.com/public/attachments/7E/EN/PRT_Modbus_7E_64_68_78_86EN.pdf77 */78
79/* 80Function readVoltage()81Description: read voltage value from the Finder energy meter holding registers82*/ 83float readVoltage() {84 float volt = 0.;85 // Send reading request over RS485 86 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x000C, 2)) {87 // Error handling88 Serial.print("- Failed to read the voltage! ");89 Serial.println(ModbusRTUClient.lastError()); 90 } else {91 // Response handler 92 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer93 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer94 uint32_t millivolt = word1 << 16 | word2; // Join word1 and word2 to retrieve voltage value in millivolts95 volt = millivolt/1000.0; // Convert to volts96 }97
98 return volt;99}100
101/* 102Function readCurrent()103Description: read current value from the Finder energy meter holding registers104*/105float readCurrent() { 106 float ampere = 0.;107 // Send reading request over RS485 108 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x0016, 2)) {109 // Error handling 110 Serial.print("- Failed to read the current! "); 111 Serial.println(ModbusRTUClient.lastError()); 112 } else { 113 // Response handler 114 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer115 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer116 int32_t milliamp = word1 << 16 | word2; // Join word1 and word2 to retrieve current value in milliampere117 ampere = milliamp/1000.0; // Convert current to ampere118 }119
120 return ampere;121}122
123/* 124Function readPower()125Description: read power value from the Finder energy meter holding registers126*/127double readPower() {128 double watt = 0.;129 // Send reading request over RS485130 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x0025, 3)) {131 // Error handling 132 Serial.print("- Failed to read power! ");133 Serial.println(ModbusRTUClient.lastError());134 } else {135 // Response handler 136 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer137 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer138 uint16_t word3 = ModbusRTUClient.read(); // Read word3 from buffer139
140 uint64_t milliwatt;141
142 // Join word1 and word2 to retrieve power value in milliwatt143 if (word1 >> 7 == 0) {144 milliwatt = word1 << 32 | word2 << 16 | word3;145 } else {146 word1 &= 0b01111111;147 milliwatt = 0b1 << 48 | word1 << 32 | word2 << 16 | word3;148 }149
150 watt = milliwatt/1000.; // Convert power to watts151 }152
153 return watt;154}155
156/* 157Function readFreq()158Description: read frequency value from the Finder energy meter holding registers159*/160float readFreq() {161 float freq = 0.;162 // Send reading request over RS485163 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x0040, 2)) {164 // Error handling 165 Serial.print("- Failed to read frequency! ");166 Serial.println(ModbusRTUClient.lastError());167 } else {168 // Response handler 169 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer170 freq = word1/1000.0; // Retrieve frequency value171 }172 return freq;173}174
175/* 176Function readEnergy()177Description: read energy value from the Finder energy meter holding registers178*/179double readEnergy() {180 double kwh = 0.;181 // Send reading request over RS485182 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x0109, 3)) {183 // Error handling 184 Serial.print("- Failed to read energy! ");185 Serial.println(ModbusRTUClient.lastError());186 } else {187 // Response handler 188 uint16_t word1 = ModbusRTUClient.read(); // Read word1 from buffer189 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer190 uint16_t word3 = ModbusRTUClient.read(); // Read word3 from buffer191 uint64_t dwh = word1 << 32 | word2 << 16 | word3; // Join word1 and word2 to retrieve energy value in dwh192 kwh = dwh/10000.0; // Convert energy to kwh193 }194 return kwh;195}
Over the Air Uploads
Did you know that the Arduino Cloud supports over the air uploads? When you've uploaded a sketch to your board once, it will become available for you to upload a new sketch to the board without connecting it to your computer!
Over the Air uploads require an Entry plan to the Arduino Cloud
To use this feature, make sure the board has power. If your board is already connected to the Cloud, you will be able to upload to it over the air. Navigate to the Things sketch tab in the Arduino Cloud interface, and you should see it being discovered just as if it was connected via USB.
Creating a Dashboard in the Arduino Cloud IoT
After our code has been successfully uploaded to our board, we we will need to create a dashboard for visualizing the energy meter data.
Create a dashboard with the following widgets:
Widget | Linked Variable |
---|---|
Value | voltage |
Value | current |
Value | power |
Value | frequency |
Value | energy |
Your dashboard should look something like this:
That's it! You have now a Modbus energy meter connected to the Arduino Cloud IoT!
Troubleshoot
Sometimes errors occur, if the code is not working or data is not in the to the Arduino Cloud IoT there are some common issues we can troubleshoot:
- Missing a bracket or a semicolon.
- Accidental interruption of cable connection.
- Wrong network credentials.
- No variable linked to a widget.
Conclusion
In this tutorial, we learned how to connect a Modbus energy meter to the Arduino Cloud IoT using a MKR WiFi 1010 board and a MKR 485 Shield. We also learned how to visualize the energy meter data in a dashboard using widgets. More tutorials? You can find them in the Arduino Cloud IoT documentation page.
Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.