Energy Monitoring with Finder 7M and OPTA

Hi all!
I present to you some code that can be used to display readings from Finder's 7M with their OPTA onto the cloud!

It is not the most streamlined or official code, more just a rough template for myself, but use as you please.

In the .ino file:

#include <Arduino.h>
#include <ArduinoModbus.h>
#include <ArduinoRS485.h>
#include <math.h>
#include "finder-7m.h"
#include "config.h"
#include "thingProperties.h"

void setup()
{
Serial.begin(9600);


RS485.setDelays(PREDELAY, POSTDELAY);
ModbusRTUClient.setTimeout(TIMEOUT);
ModbusRTUClient.begin(BAUDRATE, SERIAL_8N1);

initProperties();
ArduinoCloud.begin(ArduinoIoTPreferredConnection);


}

void loop()
{
uint32_t runTime = modbus7MRead32(ADDRESS, REG_RUN_TIME);
uint32_t energy = modbus7MRead32(ADDRESS, REG_ENERGY);
uint32_t frequency = modbus7MRead32(ADDRESS, REG_FREQUENCY);
uint32_t voltage = modbus7MRead32(ADDRESS, REG_VOLTAGE);
uint32_t activePower = modbus7MRead32(ADDRESS, REG_ACTIVE_POWER);

uint32_t Uavg = modbus7MRead32(ADDRESS, REG_Uavg);
uint32_t Iavg = modbus7MRead32(ADDRESS, REG_Iavg);
uint32_t SI = modbus7MRead32(ADDRESS, REG_SI);
uint32_t P1 = modbus7MRead32(ADDRESS, REG_P1);
uint32_t Qt = modbus7MRead32(ADDRESS, REG_Qt);

uint32_t Q1 = modbus7MRead32(ADDRESS, REG_Q1);
uint32_t St = modbus7MRead32(ADDRESS, REG_St);
uint32_t current = modbus7MRead32(ADDRESS, REG_I1);
uint32_t S1 = modbus7MRead32(ADDRESS, REG_S1);

Serial.println("Run time = " + (runTime != INVALID_DATA ? String(runTime) : String("read error")));
Serial.println("Energy = " + (energy != INVALID_DATA ? String((float)energy) : String("read error!")));
Serial.println("Frequency = " + (frequency != INVALID_DATA ? String(convertT5(frequency)) : String("read error!")));
Serial.println("Voltage = " + (voltage != INVALID_DATA ? String(convertT5(voltage)) : String("read error!")));
Serial.println("Active power = " + (activePower != INVALID_DATA ? String(convertT6(activePower)) : String("read error!")));


Serial.println("Uavg (phase to neutral) = " + (Uavg != INVALID_DATA ? String(convertT5(Uavg)) : String("read error")));
Serial.println("I1 = " + (current != INVALID_DATA ? String(convertT5(current)) : String("read error")));
Serial.println("Iavg = " + (Iavg != INVALID_DATA ? String(convertT5(Iavg)) : String("read error")));
Serial.println("S I = " + (SI != INVALID_DATA ? String(convertT5(SI)) : String("read error")));
Serial.println("Active Power Phase L1 (P1) = " + (P1 != INVALID_DATA ? String(convertT6(P1)) : String("read error")));
Serial.println("Reactive Power Total (Qt) = " + (Qt != INVALID_DATA ? String(convertT6(Qt)) : String("read error")));
Serial.println("Reactive Power Phase L1 (Q1) = " + (Q1 != INVALID_DATA ? String(convertT6(Q1)) : String("read error")));
Serial.println("Apparent Power Total (St) = " + (St != INVALID_DATA ? String(convertT5(St)) : String("read error")));
Serial.println("Apparent Power Phase L1 (S1) = " + (S1 != INVALID_DATA ? String(convertT5(S1)) : String("read error")));
Serial.println();
if (energy != INVALID_DATA)
{
cloudEnergy = float(energy);
cloudFrequency = float(convertT5(frequency));
ArduinoCloud.update();
}

delay(5000);

}

uint32_t modbus7MRead32(uint8_t address, uint16_t reg)
{
ModbusRTUClient.requestFrom(address, INPUT_REGISTERS, reg, 2);
uint32_t data1 = ModbusRTUClient.read();
uint32_t data2 = ModbusRTUClient.read();
if (data1 != INVALID_DATA && data2 != INVALID_DATA)
{
return data1 << 16 | data2;
}
else
{
return INVALID_DATA;
}
}

float convertT5(uint32_t n)
{
uint32_t s = (n & 0x80000000) >> 31;
int32_t e = (n & 0x7F000000) >> 24;
if (s == 1)
{
e = e - 0x80;
}
uint32_t m = n & 0x00FFFFFF;
return (float)m \* pow(10, e);
}

float convertT6(uint32_t n)
{
uint32_t s = (n & 0x80000000) >> 31;
int32_t e = (n & 0x7F000000) >> 24;
if (s == 1)
{
e = e - 0x80;
}
uint32_t ms = (n & 0x00800000) >> 23;
int32_t mv = (n & 0x007FFFFF);
if (ms == 1)
{
mv = mv - 0x800000;
}
return (float)mv \* pow(10, e);
}

In config.h:


#define WIFI_SECRET_SSID "Your SSID"

#define WIFI_SECRET_PASSWORD "Your SSID Password"

// ArduinoCloud specific configuration

#define ARDUINO_CLOUD_USE_WIFI 1

In finder-7m.h:

// Configurazione
#define ADDRESS 2
#define BAUDRATE 19200
#define PREDELAY 1750
#define POSTDELAY 1750
#define TIMEOUT 1000

// Registri
#define REG_RUN_TIME 103     // Run time
#define REG_FREQUENCY 105    // Frequency
#define REG_VOLTAGE 107      // Voltage U1
#define REG_ACTIVE_POWER 140 // Active Power
#define REG_ENERGY 406       // MID certified active energy
#define REG_Uavg  113
#define REG_I1  126
#define REG_Iavg 136
#define REG_SI  138
#define REG_P1  142
#define REG_Qt  148
#define REG_Q1  150
#define REG_St  156
#define REG_S1  158

// Errore di lettura
#define INVALID_DATA 0xFFFFFFFF

Make address and baudrate the same on the 7M.
These registers can be found on the modbus sheet for the 7M via the Finder website.

In thingProperties.h:

#include <ArduinoIoTCloud.h>

#include <Arduino_ConnectionHandler.h>

#include "config.h"

const char SSID\[\] = WIFI_SECRET_SSID;

const char PASS\[\] = WIFI_SECRET_PASSWORD;

float cloudEnergy;

float cloudFrequency;

void initProperties()

{

ArduinoCloud.addProperty(cloudEnergy, Permission::Read);

ArduinoCloud.addProperty(cloudFrequency, Permission::Read);

}

#if ARDUINO_CLOUD_USE_WIFI == 1

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);

#else

EthernetConnectionHandler ArduinoIoTPreferredConnection;

#endif

Notes:
These are working with the cloud and being displayed on a dashboard.

I have added a lot more variables than are actually displayed on the dash (at the moment only Energy and Frequency are).
Whenever I add a new 'thing variable' via the Arduino cloud app/interface that I would like displayed, the thingProperties.h file gets overwritten and the program does not work so I manually add and write each one. Will potentially find a fix later but any ideas appreciated.