Skip to content

Library for accessing Continental Controlls WattNode Modbus

License

Notifications You must be signed in to change notification settings

mcci-catena/MCCI-WattNode-Modbus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCCI-WattNode-Modbus

Header files and code for working with the Continental Controls WattNode® Modbus energy meters.

Overview

This library defines C++ classes that encapsulate the Modbus register definitions for the Continental Control Systems WattNode Modbus electric power meters. In addition to register definitions, utility functions are provided for converting between higher level data types and 16-bit Modbus register values.

Header Files

MCCI-WattNode-Modbus-Registers.h

This header file defines the classes listed under Classes, below.

MCCI-WattNode-Modbus-tuple.h

This auxiliary header file wraps the standard C++ header file <tuple>, compensating for some of the complications of the Arduino environment.

Namespaces

All C++ names are declared in a single namespace McciWattNodeModbus. In the rest of this document, we assume that you have written:

using namespace McciWattNodeModbus;

Of course, this is not a requirement; you can use the namespace on each reference, at the cost of a lot more typing.

Classes

WattNodeModbus_Framework

class WattNodeModbus_Framework;

This class defines the common static methods exported by the concrete WattNodeModbus classes.

WattNode_WNC

class WattNode_WNC : public WattNodeModbus_Framework;

This class extends WattNodeModbus_Framework by defining enum Register, which in turn defines the various register names for the WattNode WNC meter. See Registers for general considerations.

WattNode_WND

class WattNode_WND : public WattNodeModbus_Framework;

This class extends WattNodeModbus_Framework by defining enum Register, which in turn defines the various register names for the WattNode WND module. See Registers for general considerations.

Registers

The names of registers follow a common format, RegisterName_type, where RegisterName matches the name used in the Continental Controls manual, and type is a reminder of the numeric type to be used for the register. The type is one of the following:

type Description
i32 The value of the enum is the address of the first register of a pair of registers, which are to be combined and treated as a 32-bit twos-complement signed integer. The lower-numbered register is the low-order word.
f32 The value of the enum is the address of the first register of a pair of registers, which are to be combined and treated as a 32-bit IEEE floating point number. The lower-numbered register is the low-order word.
i16 The value of the enum is the address of a 16-bit register, which is to be treated as a 16-bit twos-complement signed integer.
u16 The value of the enum is the address of 16-bit register, which is to be treated as a 16-bit unsigned integer.
vu16 The value of the enum is the address of the first register in a vector of registers.

Note: all register values are origin-1, to match Continental Controls documentation and Modbus convention.

Static Methods

getAddress()

constexpr uint16_t WattNodeModbus_WNx::getAddress(Register r);

This function converts a register value to an address suitable to passing over the wire, by converting the origin-1 Register value to origin-0.

getRegister()

constexpr Register WattNodeModbus_WNx::getRegister(uint16_t address);

This function converts a Modbus address into the the equivalent Register value. It doesn't check whether the address matches any known register, it just blindly does a type conversion.

regval_getfloat()

static float WattNodeModbus_WNx::regval_getfloat(int16_t vLow, int16_t vHigh);
static float WattNodeModbus_WNx::regval_getfloat(int16_t vLow, int16_t vHigh, bool *pError);

Given two values read from consecutive registers, create the equivalent IEEE floating point number. In order to avoid run-time exceptions, IEEE NAN values are converted to zero. If pError is supplied and is not nullptr, then *pError is set true if a NAN is encountered. Otherwise *pError is not changed.

float_getregval()

static std::tuple<int16_t, int16_t>
WattNodeModbus_WNx::float_getregval(
    float vFloat
    );

Converts a floating-point value to the equivalent pair of registers to be transmitted over the wire. The result is a tuple with the first word being the low-order register value, and the second word being the high-order register value. Here's an example.

int16_t vLow, vHigh;
float vFloat = // something;
std::tie(vLow, vHigh) = WattNodeModbus_WNx::float_getregval(vFloat);

regval_getuint32()

static int32_t
WattNodeModbus_WNx::regval_getint32(
    int16_t vLow, int16_t vHigh
    );

Given two 16-bit values read from consecutive registers, create the equivalent 32-bit integer.

int32_getregval()

static std::tuple<int16_t, int16_t>
WattNodeModbus_WNx::int32_getregval(
    int32_t vInt32
    );

Convert an int32_t value into the equivalent pair of 16-bit values to be placed into consecutive registers. The result is a tuple with the first word being the low-order register value, and the second word being the high-order register value. Here's an example.

int16_t vLow, vHigh;
int32_t vInt32 = /* some value */;

std::tie(vLow, vHigh) = WattNodeModbus_WNx::int32_getregval(vInt32);

Supported meters

We've used this library with the following meters.

References

All this data is based on downloads from Continental Control Systems' website, ctlsys.com.

The spreadsheets we used to help with this work are in extras.

The original spreadsheet was the reference for WND series, the V1.8 Register List

This was updated in April 2019 based on the WND-Module-Modubs-Register-List-v1028. We took their word for the names of the new registers.

Procedure For Generating Spreadsheet

Duplicate first sheet of spreadsheet.

Rename first sheet "Main List", and copy "Flattened".

From now own, all work is in the "Flattened" sheet.

Delete lines above the section title, e.g. "Basic Registers - Floating Point" or "Measurement Register List - Floating-Point"

Insert a new column at column A (so you have two blank columns on the left).

We're going to pivot the top-level headers into column A, and pivot level-two header into column B. While doing that, normalize the titles so that we have "floating point" or "integer" in the f32 or i32 registers.

It's fastest to pivot layer 2 first.

Then delete line 1, select all, turn on filtering, and use filtering to make it easier to find the header rows. Delete them.

Insert two columns to right of "registers". Copy "Base (hex)" and "Base (dec, origin-1)" from an earlier sheet. Formulas:

Column Formula
Base (hex) =DEC2HEX(NUMBERVALUE(LEFT(E2,IFERROR(SEARCH(",",E2)-1,LEN(E2))))-1)
Base (dec) =HEX2DEC(F2)+1
Size =IF(IFERROR(SEARCH(",",E2),0)<>0, 2, 1)

Similarly, insert 4 columns to right of "Name", and copy/paste from an earlier sheet. Formulae:

Column Formula
Size =IF(IFERROR(SEARCH(",",C2),0)<>0, 2, 1)
Type =IF(IFERROR(SEARCH("floating point",A2),0)<>0, "float", IF(G2>1, "int32_t", "int16_t"))
C++ name =CONCAT(F2,"_",LEFT(H2,1),16*G2)
Enum =CONCAT(I2, IF(IFERROR(E2-E1<>1,TRUE),CONCAT(" = ",E2),CONCAT(" /* = ", E2, " */")),",")

Fill down to fill the inserted columns with formula.

Sort ascending on "Base (dec, origin-1)".

Acknowledgements

WattNode is a registered trademark of Continental Controls. MCCI and MCCI Catena are registered trademarks of MCCI Corporation. All other trademarks are the properties of their respective owners.

About

Library for accessing Continental Controlls WattNode Modbus

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published