Monitor Your Energy Bill with Modbus and the Arduino IoT 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.

Goals

The goals with this tutorial are:

Hardware and Software Needed

The hardware and software used in this tutorial:

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.

An analog energy meter (source: General Electric)
An analog energy meter (source: General Electric)

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.

Finder Type 73.64 Energy Meter (source: Finder)
Finder Type 73.64 Energy Meter (source: Finder)

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.

Main voltage connections. Wires above are inputs, wires below are outputs
Main voltage connections. Wires above are inputs, wires below are outputs

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.

Energy meter RS-485 interface connections
Energy meter RS-485 interface connections

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:

MKR 485 Shield setup and connections
MKR 485 Shield setup and connections

Now, we can connect the MKR 485 Shield and the MKR WiFi 1010 board:

MKR 485 Shield setup and connections
MKR 485 Shield setup and connections

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

First, we need to register and configure our MKR WiFi 1010 board in the Arduino Cloud IoT. Let's start by navigating to Arduino Cloud IoT.

Note: You will need a Arduino account to use the Arduino Cloud IoT. If you do not have one, you will be redirected to the account registration site.

Configure a New Device in the Arduino Cloud IoT

Once we are in the Arduino Cloud IoT, we will need to select "Devices" tab. This will open a new page which will ask you to add a new device. Click on the "ADD DEVICE" button.

Adding a new device to our Arduino Clout IoT account
Adding a new device to our Arduino Clout IoT account

In the set up wizard, we will now have an option of either configuring a new Arduino® device, or a third party device. Let's select the "Set up an Arduino device" option.

Selecting the type of device to set up
Selecting the type of device to set up

At this point, we will need to connect our MKR WiFi 1010 board to our computer; we will also need to have installed the Arduino Create Agent in our computer. If the Arduino Create Agent is not installed, the set up wizard will ask us to install it. Our device should now show up as shown in the image below. Now its time to configure it, let's select the "CONFIGURE" button.

MKR WiFi 1010 board found!
MKR WiFi 1010 board found!

Now we must name our device. In this case, we named our device as "EnergyMeter001"; names can be randomly generated also by the set up wizard. Let's continue by selecting the "NEXT" button.

Naming our MKR WiFi 1010 board
Naming our MKR WiFi 1010 board

After selecting the "NEXT" button, the set up wizard will start to configure our board. This process may take a few minutes.

Configuration process of our MKR WiFi 1010 board and the Arduino Cloud IoT
Configuration process of our MKR WiFi 1010 board and the Arduino Cloud IoT

Once it is done, select the "DONE" button, we will be redirected to the "Devices" page. In this page we are going to be able to see our device. Congratulations! The configuration of our board and the Arduino Cloud IoT is done, now we can create a "Thing" with it.

Configuration process of our MKR WiFi 1010 board and the Arduino Cloud IoT
Configuration process of our MKR WiFi 1010 board and the Arduino Cloud IoT

Create a New Thing in the Arduino Cloud IoT

After our board is configured in the Arduino Cloud IoT, we can move on to the next step: creating a "Thing". Let's select the "Things" tab and then select the "CREATE THING" button.

Creation of a "Thing" in the Arduino Cloud IoT complete
Creation of a "Thing" in the Arduino Cloud IoT complete

We will be redirected to a page with our "Thing" configuration overview. Here we can define our "Thing" name, select to what network we are connecting to, what device we are using with out "Thing" and create variables that we want to to connect from our board to our "Thing" in the Arduino Cloud IoT.

Overview of a "Thing" in the Arduino Cloud IoT
Overview of a "Thing" in the Arduino Cloud IoT

Let's start by giving a name to our "Thing" and linking our freshly configured device. We named our Thing as "Energy Thing", this can be done by clicking in "Untitled". To link out freshly configured device, we select the "Select Device" button located to the right. This will open up a window where we can associate a previously configured device with our "Thing" by selecting the "ASSOCIATE" button.

Associating a device to a "Thing" in the Arduino Cloud IoT
Associating a device to a "Thing" in the Arduino Cloud IoT

Creating Variables for a "Thing" in the Arduino Cloud IoT

Now, let's create variables for the "Energy Thing". The variables we are going to create will be synced, automatically, with the Arduino Cloud IoT as long as the board is connected to Internet and the Arduino Cloud IoT. Let's create create a new variable by selecting the "Add Variable" button.

"ADD VARIABLE" button in the Arduino Cloud IoT
"ADD VARIABLE" button in the Arduino Cloud IoT

This will open up a window where we can create new variables and define its characteristics. The first variable we are going to create will be named "voltage"; this variable will have the following characteristics:

  • Variable type: Floating Point Number.
  • Variable permission: read only.
  • Variable update policy: on change (threshold do not changes).

Adding a variable to the "Energy Thing"
Adding a variable to the "Energy Thing"

Repeat this process for the variables and its characteristics shown in the table below:

VariableTypePermissionUpdate Policy
voltageFloating Point NumberRead OnlyOn change
currentFloating Point NumberRead OnlyOn change
powerFloating Point NumberRead OnlyOn change
frequencyFloating Point NumberRead OnlyOn change
energyFloating Point NumberRead OnlyOn change

The created variables should appear now in the "Energy Thing" overview.

Variables of the "Energy Thing"
Variables of the "Energy Thing"

Network Credentials for a "Thing" in the Arduino Cloud IoT

Now that we have created the variables for the "Energy Thing", we can configure the network details. This can be done by selecting the "Configure" button in the "Network" section. This will open up a window where we can add the network SSID and its password.

Network credentiales of the "Energy Thing"
Network credentiales of the "Energy Thing"

Creating an 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.

Sketch tab in the Arduino Cloud IoT
Sketch tab in the Arduino Cloud IoT

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:

  • 0x01
    is the device address.
  • 0x03
    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.
  • 0x04
    for byte count, this specifies how may data items are being returned.
  • 00 16
    is register address from the Modbus device we want to read.
  • 00 02
    is the size of the register in words (every word is 2 bytes long).
  • 25 C7
    is a CRC code. This code is generated from a math function over previous bytes, it ensures that the message has been received correctly.

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 registers
4
5Created by Alberto Perro (Officine Innesto)
6Modified by José Bagur
7*/
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 buffer
19 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
20 int32_t milliamp = word1 << 16 | word2; // Join word1 and word2 to retrieve current value in milliampere
21 ampere = milliamp/1000.0; // Convert current to ampere
22 }
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 IoT
3 * -----------------------------------------
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é Bagur
10*/
11
12#include <ArduinoRS485.h>
13#include <ArduinoModbus.h>
14
15#undef ON
16#undef OFF
17
18#include "thingProperties.h"
19
20unsigned long rate = 60000; // Default refresh rate in ms
21unsigned long lastMillis = 0;
22
23void setup() {
24 // Initialize serial port at 9600 bauds and wait for it to open
25 Serial.begin(9600);
26 delay(1500);
27
28 // Defined in thingProperties.h
29 initProperties();
30
31 // Connect to Arduino Cloud IoT
32 ArduinoCloud.begin(ArduinoIoTPreferredConnection);
33
34 /*
35 The following function allows you to obtain more information
36 related to the state of network and Cloud IoT connection and errors
37 The higher number the more granular information you’ll get
38 The default value is 0 (only errors)
39 Maximum is 4
40 */
41 setDebugMessageLevel(2);
42 ArduinoCloud.printDebugInfo();
43
44 // Start Modbus RTU client
45 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 IoT
53 ArduinoCloud.update();
54
55 // Update energy meter data and show it via the Serial Monitor
56 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 registers
76 * For more information: https://gfinder.findernet.com/public/attachments/7E/EN/PRT_Modbus_7E_64_68_78_86EN.pdf
77 */
78
79/*
80Function readVoltage()
81Description: read voltage value from the Finder energy meter holding registers
82*/
83float readVoltage() {
84 float volt = 0.;
85 // Send reading request over RS485
86 if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x000C, 2)) {
87 // Error handling
88 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 buffer
93 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
94 uint32_t millivolt = word1 << 16 | word2; // Join word1 and word2 to retrieve voltage value in millivolts
95 volt = millivolt/1000.0; // Convert to volts
96 }
97
98 return volt;
99}
100
101/*
102Function readCurrent()
103Description: read current value from the Finder energy meter holding registers
104*/
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 buffer
115 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
116 int32_t milliamp = word1 << 16 | word2; // Join word1 and word2 to retrieve current value in milliampere
117 ampere = milliamp/1000.0; // Convert current to ampere
118 }
119
120 return ampere;
121}
122
123/*
124Function readPower()
125Description: read power value from the Finder energy meter holding registers
126*/
127double readPower() {
128 double watt = 0.;
129 // Send reading request over RS485
130 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 buffer
137 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
138 uint16_t word3 = ModbusRTUClient.read(); // Read word3 from buffer
139
140 uint64_t milliwatt;
141
142 // Join word1 and word2 to retrieve power value in milliwatt
143 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 watts
151 }
152
153 return watt;
154}
155
156/*
157Function readFreq()
158Description: read frequency value from the Finder energy meter holding registers
159*/
160float readFreq() {
161 float freq = 0.;
162 // Send reading request over RS485
163 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 buffer
170 freq = word1/1000.0; // Retrieve frequency value
171 }
172 return freq;
173}
174
175/*
176Function readEnergy()
177Description: read energy value from the Finder energy meter holding registers
178*/
179double readEnergy() {
180 double kwh = 0.;
181 // Send reading request over RS485
182 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 buffer
189 uint16_t word2 = ModbusRTUClient.read(); // Read word2 from buffer
190 uint16_t word3 = ModbusRTUClient.read(); // Read word3 from buffer
191 uint64_t dwh = word1 << 32 | word2 << 16 | word3; // Join word1 and word2 to retrieve energy value in dwh
192 kwh = dwh/10000.0; // Convert energy to kwh
193 }
194 return kwh;
195}

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. Head over to the "Dashboards" tab and click on "Build Dashboard".

Dashboards tab in the Arduino Cloud IoT
Dashboards tab in the Arduino Cloud IoT

An empty dashboard will be displayed. After changing the new dashboard's name, for example "Energy Meter Dashboard", let's add widgets to it. Let's click on the "ADD" button and select a "Value" widget.

Adding a value widget into a dashboard in the Arduino Cloud IoT
Adding a value widget into a dashboard in the Arduino Cloud IoT

Now, we need to link the widget we just added to our dashboard to one of the energy meter variables we defined previously in the "Energy Thing" (voltage, current, power, frequency and energy). This can be done by selecting the "Link Variable" button and then selecting the variable you want to link with the widget; let's start with the variable voltage; remember also to give a name to the widget.

Linking a variable to a widget in the Arduino Cloud IoT
Linking a variable to a widget in the Arduino Cloud IoT

Follow the steps described above to link the rest of the variables of the "Energy Thing" to value widgets. We should see now all of the energy meter data being displayed on the dashboard, the data shown should update every

60000
ms when our MKR WiFi 1010 board is connected to the Arduino Cloud IoT.

Energy meter data shown in the Arduino Cloud IoT
Energy meter data shown in the Arduino Cloud IoT

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.

Contribute to Arduino

Join the community and suggest improvements to this article via GitHub. Make sure to read out contribution policy before making your pull request.

Missing something?

Check out our store and get what you need to follow this tutorial.

Suggest Changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. You can read more on how to contribute in the contribution policy.