mirror of
https://github.com/eclipse/upm.git
synced 2025-03-15 04:57:30 +03:00
h803x: Initial implementation
This module implements support for the Veris H8035 and H8036 Energy Meters. The H8036 is similar to the H8035, but provides much more data. The Enercept H8035/H8036 is an innovative three-phase networked (Modbus RTU) power transducer that combines electronics and high accuracy industrial grade CTs in a single package. The need for external electrical enclosures is eliminated, greatly reducing installation time and cost. Color-coordination between voltage leads and CTs makes phase matching easy. Additionally, these transducers automatically detect and compensate for phase reversal, eliminating the concern of CT load orientation. Up to 63 Transducers can be daisy-chained on a single RS-485 network. This module was developed using libmodbus 3.1.2, and the H8035. The H8036 has not been tested. libmodbus 3.1.2 must be present for this module to build. Signed-off-by: Jon Trulson <jtrulson@ics.com> Signed-off-by: Abhishek Malik <abhishek.malik@intel.com>
This commit is contained in:
parent
e062b9b85c
commit
5a5637a431
@ -234,6 +234,7 @@ if (MODBUS_FOUND)
|
||||
include_directories(${MODBUS_INCLUDE_DIRS})
|
||||
add_example (t3311)
|
||||
add_example (hwxpxx)
|
||||
add_example (h803x)
|
||||
endif()
|
||||
add_example (hdxxvxta)
|
||||
add_example (rhusb)
|
||||
|
149
examples/c++/h803x.cxx
Normal file
149
examples/c++/h803x.cxx
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
|
||||
#include "h803x.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool shouldRun = true;
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
shouldRun = false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
//! [Interesting]
|
||||
|
||||
string defaultDev = "/dev/ttyUSB0";
|
||||
|
||||
// if an argument was specified, use it as the device instead
|
||||
if (argc > 1)
|
||||
defaultDev = string(argv[1]);
|
||||
|
||||
cout << "Using device " << defaultDev << endl;
|
||||
cout << "Initializing..." << endl;
|
||||
|
||||
// Instantiate an H803X instance, using MODBUS slave address 1, and
|
||||
// default comm parameters (9600, 8, N, 2)
|
||||
upm::H803X *sensor = new upm::H803X(defaultDev, 1);
|
||||
|
||||
// output the Slave ID string
|
||||
cout << "Slave ID: " << sensor->getSlaveID() << endl;
|
||||
cout << endl;
|
||||
|
||||
// update and print available values every second
|
||||
while (shouldRun)
|
||||
{
|
||||
// update our values from the sensor
|
||||
sensor->update();
|
||||
|
||||
// H8035 / H8036
|
||||
cout << "Consumption (kWh): " << sensor->getConsumption() << endl;
|
||||
cout << "Real Power (kW): " << sensor->getRealPower() << endl;
|
||||
|
||||
if (sensor->isH8036())
|
||||
{
|
||||
// The H8036 has much more data available...
|
||||
|
||||
cout << "Reactive Power (kVAR): " << sensor->getReactivePower()
|
||||
<< endl;
|
||||
cout << "Apparent Power (kVA): " << sensor->getApparentPower()
|
||||
<< endl;
|
||||
cout << "Power Factor: " << sensor->getPowerFactor()
|
||||
<< endl;
|
||||
cout << "Volts Line to Line: " << sensor->getVoltsLineToLine()
|
||||
<< endl;
|
||||
cout << "Volts Line to Neutral: " << sensor->getVoltsLineToNeutral()
|
||||
<< endl;
|
||||
|
||||
cout << "Current: " << sensor->getCurrent()
|
||||
<< endl;
|
||||
|
||||
cout << "Real Power Phase A (kW): " << sensor->getRealPowerPhaseA()
|
||||
<< endl;
|
||||
cout << "Real Power Phase B (kW): " << sensor->getRealPowerPhaseB()
|
||||
<< endl;
|
||||
cout << "Real Power Phase C (kW): " << sensor->getRealPowerPhaseC()
|
||||
<< endl;
|
||||
|
||||
cout << "Power Factor Phase A: " << sensor->getPowerFactorPhaseA()
|
||||
<< endl;
|
||||
cout << "Power Factor Phase B: " << sensor->getPowerFactorPhaseB()
|
||||
<< endl;
|
||||
cout << "Power Factor Phase C: " << sensor->getPowerFactorPhaseC()
|
||||
<< endl;
|
||||
|
||||
cout << "Volts Phase A to B: " << sensor->getVoltsPhaseAToB()
|
||||
<< endl;
|
||||
cout << "Volts Phase B to C: " << sensor->getVoltsPhaseBToC()
|
||||
<< endl;
|
||||
cout << "Volts Phase A to C: " << sensor->getVoltsPhaseAToC()
|
||||
<< endl;
|
||||
cout << "Volts Phase A to Neutral: "
|
||||
<< sensor->getVoltsPhaseAToNeutral()
|
||||
<< endl;
|
||||
cout << "Volts Phase B to Neutral: "
|
||||
<< sensor->getVoltsPhaseBToNeutral()
|
||||
<< endl;
|
||||
cout << "Volts Phase C to Neutral: "
|
||||
<< sensor->getVoltsPhaseCToNeutral()
|
||||
<< endl;
|
||||
|
||||
cout << "Current Phase A: " << sensor->getCurrentPhaseA()
|
||||
<< endl;
|
||||
cout << "Current Phase B: " << sensor->getCurrentPhaseB()
|
||||
<< endl;
|
||||
cout << "Current Phase C: " << sensor->getCurrentPhaseC()
|
||||
<< endl;
|
||||
|
||||
cout << "Avg Real Power (kW): " << sensor->getAvgRealPower()
|
||||
<< endl;
|
||||
cout << "Min Real Power (kW): " << sensor->getMinRealPower()
|
||||
<< endl;
|
||||
cout << "Max Real Power (kW): " << sensor->getMaxRealPower()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
cout << "Exiting..." << endl;
|
||||
|
||||
delete sensor;
|
||||
|
||||
//! [Interesting]
|
||||
|
||||
return 0;
|
||||
}
|
@ -110,6 +110,9 @@ add_example(TEAMS_Example teams)
|
||||
add_example(APA102Sample apa102)
|
||||
add_example(TEX00_Example tex00)
|
||||
add_example(BMI160_Example bmi160)
|
||||
if (MODBUS_FOUND)
|
||||
add_example(H803X_Example h803x)
|
||||
endif()
|
||||
|
||||
add_example_with_path(Jhd1313m1_lcdSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(Jhd1313m1Sample lcd/upm_i2clcd.jar)
|
||||
|
123
examples/java/H803X_Example.java
Normal file
123
examples/java/H803X_Example.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import upm_h803x.H803X;
|
||||
|
||||
public class H803X_Example
|
||||
{
|
||||
private static String defaultDev = "/dev/ttyUSB0";
|
||||
|
||||
public static void main(String[] args) throws InterruptedException
|
||||
{
|
||||
// ! [Interesting]
|
||||
if (args.length > 0)
|
||||
defaultDev = args[0];
|
||||
System.out.println("Using device " + defaultDev);
|
||||
System.out.println("Initializing...");
|
||||
|
||||
// Instantiate an H803X instance, using MODBUS slave address 1, and
|
||||
// default comm parameters (9600, 8, N, 2)
|
||||
H803X sensor = new H803X(defaultDev, 1);
|
||||
|
||||
// output the Slave ID (manufacturer, model, serno)
|
||||
System.out.println("Slave ID: " + sensor.getSlaveID());
|
||||
System.out.println();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// update our values from the sensor
|
||||
sensor.update();
|
||||
|
||||
// H8035 / H8036
|
||||
System.out.println("Consumption (kWh): "
|
||||
+ sensor.getConsumption());
|
||||
System.out.println("Real Power (kW): "
|
||||
+ sensor.getRealPower());
|
||||
|
||||
if (sensor.isH8036())
|
||||
{
|
||||
// The H8036 has much more data available...
|
||||
|
||||
System.out.println("Reactive Power (kVAR): "
|
||||
+ sensor.getReactivePower());
|
||||
System.out.println("Apparent Power (kVA): "
|
||||
+ sensor.getApparentPower());
|
||||
System.out.println("Power Factor: "
|
||||
+ sensor.getPowerFactor());
|
||||
System.out.println("Volts Line to Line: "
|
||||
+ sensor.getVoltsLineToLine());
|
||||
System.out.println("Volts Line to Neutral: "
|
||||
+ sensor.getVoltsLineToNeutral());
|
||||
|
||||
System.out.println("Current: " + sensor.getCurrent());
|
||||
|
||||
System.out.println("Real Power Phase A (kW): "
|
||||
+ sensor.getRealPowerPhaseA());
|
||||
System.out.println("Real Power Phase B (kW): "
|
||||
+ sensor.getRealPowerPhaseB());
|
||||
System.out.println("Real Power Phase C (kW): "
|
||||
+ sensor.getRealPowerPhaseC());
|
||||
|
||||
System.out.println("Power Factor Phase A: "
|
||||
+ sensor.getPowerFactorPhaseA());
|
||||
System.out.println("Power Factor Phase B: "
|
||||
+ sensor.getPowerFactorPhaseB());
|
||||
System.out.println("Power Factor Phase C: "
|
||||
+ sensor.getPowerFactorPhaseC());
|
||||
|
||||
System.out.println("Volts Phase A to B: "
|
||||
+ sensor.getVoltsPhaseAToB());
|
||||
System.out.println("Volts Phase B to C: "
|
||||
+ sensor.getVoltsPhaseBToC());
|
||||
System.out.println("Volts Phase A to C: "
|
||||
+ sensor.getVoltsPhaseAToC());
|
||||
System.out.println("Volts Phase A to Neutral: "
|
||||
+ sensor.getVoltsPhaseAToNeutral());
|
||||
System.out.println("Volts Phase B to Neutral: "
|
||||
+ sensor.getVoltsPhaseBToNeutral());
|
||||
System.out.println("Volts Phase C to Neutral: "
|
||||
+ sensor.getVoltsPhaseCToNeutral());
|
||||
|
||||
System.out.println("Current Phase A: "
|
||||
+ sensor.getCurrentPhaseA());
|
||||
System.out.println("Current Phase B: "
|
||||
+ sensor.getCurrentPhaseB());
|
||||
System.out.println("Current Phase C: "
|
||||
+ sensor.getCurrentPhaseC());
|
||||
|
||||
System.out.println("Avg Real Power (kW): "
|
||||
+ sensor.getAvgRealPower());
|
||||
System.out.println("Min Real Power (kW): "
|
||||
+ sensor.getMinRealPower());
|
||||
System.out.println("Max Real Power (kW): "
|
||||
+ sensor.getMaxRealPower());
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
|
||||
// ! [Interesting]
|
||||
}
|
||||
}
|
115
examples/javascript/h803x.js
Normal file
115
examples/javascript/h803x.js
Normal file
@ -0,0 +1,115 @@
|
||||
/*jslint node:true, vars:true, bitwise:true, unparam:true */
|
||||
/*jshint unused:true */
|
||||
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
var sensorObj = require('jsupm_h803x');
|
||||
|
||||
|
||||
/************** Main code **************/
|
||||
|
||||
var defaultDev = "/dev/ttyUSB0";
|
||||
|
||||
// if an argument was specified, use it as the device instead
|
||||
if (process.argv.length > 2)
|
||||
{
|
||||
defaultDev = process.argv[2];
|
||||
}
|
||||
|
||||
console.log("Using device " + defaultDev);
|
||||
console.log("Initializing...");
|
||||
|
||||
// Instantiate an H803X instance, using MODBUS slave address 1, and
|
||||
// default comm parameters (9600, 8, N, 2)
|
||||
var sensor = new sensorObj.H803X(defaultDev, 1);
|
||||
|
||||
// output the Slave ID (manufacturer, model, serno)
|
||||
console.log("Slave ID:", sensor.getSlaveID());
|
||||
|
||||
console.log("");
|
||||
|
||||
// update and print available values every second
|
||||
setInterval(function()
|
||||
{
|
||||
// update our values from the sensor
|
||||
sensor.update();
|
||||
|
||||
// H8035 / H8036
|
||||
console.log("Consumption (kWh):", sensor.getConsumption());
|
||||
console.log("Real Power (kW):", sensor.getRealPower());
|
||||
|
||||
if (sensor.isH8036())
|
||||
{
|
||||
// The H8036 has much more data available...
|
||||
|
||||
console.log("Reactive Power (kVAR):", sensor.getReactivePower());
|
||||
console.log("Apparent Power (kVA):", sensor.getApparentPower());
|
||||
console.log("Power Factor:", sensor.getPowerFactor());
|
||||
console.log("Volts Line to Line:", sensor.getVoltsLineToLine());
|
||||
console.log("Volts Line to Neutral:", sensor.getVoltsLineToNeutral());
|
||||
|
||||
console.log("Current:", sensor.getCurrent());
|
||||
|
||||
console.log("Real Power Phase A (kW):", sensor.getRealPowerPhaseA());
|
||||
console.log("Real Power Phase B (kW):", sensor.getRealPowerPhaseB());
|
||||
console.log("Real Power Phase C (kW):", sensor.getRealPowerPhaseC());
|
||||
|
||||
console.log("Power Factor Phase A:", sensor.getPowerFactorPhaseA());
|
||||
console.log("Power Factor Phase B:", sensor.getPowerFactorPhaseB());
|
||||
console.log("Power Factor Phase C:", sensor.getPowerFactorPhaseC());
|
||||
|
||||
console.log("Volts Phase A to B:", sensor.getVoltsPhaseAToB());
|
||||
console.log("Volts Phase B to C:", sensor.getVoltsPhaseBToC());
|
||||
console.log("Volts Phase A to C:", sensor.getVoltsPhaseAToC());
|
||||
console.log("Volts Phase A to Neutral: ",
|
||||
sensor.getVoltsPhaseAToNeutral());
|
||||
console.log("Volts Phase B to Neutral: ",
|
||||
sensor.getVoltsPhaseBToNeutral());
|
||||
console.log("Volts Phase C to Neutral: ",
|
||||
sensor.getVoltsPhaseCToNeutral());
|
||||
|
||||
console.log("Current Phase A:", sensor.getCurrentPhaseA());
|
||||
console.log("Current Phase B:", sensor.getCurrentPhaseB());
|
||||
console.log("Current Phase C:", sensor.getCurrentPhaseC());
|
||||
|
||||
console.log("Avg Real Power (kW):", sensor.getAvgRealPower());
|
||||
console.log("Min Real Power (kW):", sensor.getMinRealPower());
|
||||
console.log("Max Real Power (kW):", sensor.getMaxRealPower());
|
||||
}
|
||||
|
||||
console.log("");
|
||||
|
||||
}, 2000);
|
||||
|
||||
|
||||
process.on('SIGINT', function()
|
||||
{
|
||||
sensor = null;
|
||||
sensorObj.cleanUp();
|
||||
sensorObj = null;
|
||||
console.log("Exiting...");
|
||||
process.exit(0);
|
||||
});
|
106
examples/python/h803x.py
Normal file
106
examples/python/h803x.py
Normal file
@ -0,0 +1,106 @@
|
||||
#!/usr/bin/python
|
||||
# Author: Jon Trulson <jtrulson@ics.com>
|
||||
# Copyright (c) 2016 Intel Corporation.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import time, sys, signal, atexit
|
||||
import pyupm_h803x as sensorObj
|
||||
|
||||
## Exit handlers ##
|
||||
# This function stops python from printing a stacktrace when you hit control-C
|
||||
def SIGINTHandler(signum, frame):
|
||||
raise SystemExit
|
||||
|
||||
# This function lets you run code on exit
|
||||
def exitHandler():
|
||||
print "Exiting..."
|
||||
sys.exit(0)
|
||||
|
||||
# Register exit handlers
|
||||
atexit.register(exitHandler)
|
||||
signal.signal(signal.SIGINT, SIGINTHandler)
|
||||
|
||||
defaultDev = "/dev/ttyUSB0"
|
||||
|
||||
# if an argument was specified, use it as the device instead
|
||||
if (len(sys.argv) > 1):
|
||||
defaultDev = sys.argv[1]
|
||||
|
||||
print "Using device", defaultDev
|
||||
print "Initializing..."
|
||||
|
||||
# Instantiate an H803X instance, using MODBUS slave address 1, and
|
||||
# default comm parameters (9600, 8, N, 2)
|
||||
sensor = sensorObj.H803X(defaultDev, 1)
|
||||
|
||||
# output the serial number and firmware revision
|
||||
print "Slave ID:", sensor.getSlaveID()
|
||||
|
||||
print
|
||||
|
||||
# update and print available values every second
|
||||
while (1):
|
||||
# update our values from the sensor
|
||||
sensor.update()
|
||||
|
||||
# H8035 / H8036
|
||||
print "Consumption (kWh):", sensor.getConsumption()
|
||||
print "Real Power (kW):", sensor.getRealPower()
|
||||
|
||||
if (sensor.isH8036()):
|
||||
# The H8036 has much more data available...
|
||||
|
||||
print "Reactive Power (kVAR):", sensor.getReactivePower()
|
||||
print "Apparent Power (kVA):", sensor.getApparentPower()
|
||||
print "Power Factor:", sensor.getPowerFactor()
|
||||
print "Volts Line to Line:", sensor.getVoltsLineToLine()
|
||||
print "Volts Line to Neutral:", sensor.getVoltsLineToNeutral()
|
||||
|
||||
print "Current:", sensor.getCurrent()
|
||||
|
||||
print "Real Power Phase A (kW):", sensor.getRealPowerPhaseA()
|
||||
print "Real Power Phase B (kW):", sensor.getRealPowerPhaseB()
|
||||
print "Real Power Phase C (kW):", sensor.getRealPowerPhaseC()
|
||||
|
||||
print "Power Factor Phase A:", sensor.getPowerFactorPhaseA()
|
||||
print "Power Factor Phase B:", sensor.getPowerFactorPhaseB()
|
||||
print "Power Factor Phase C:", sensor.getPowerFactorPhaseC()
|
||||
|
||||
print "Volts Phase A to B:", sensor.getVoltsPhaseAToB()
|
||||
print "Volts Phase B to C:", sensor.getVoltsPhaseBToC()
|
||||
print "Volts Phase A to C:", sensor.getVoltsPhaseAToC()
|
||||
print "Volts Phase A to Neutral: ",
|
||||
print sensor.getVoltsPhaseAToNeutral()
|
||||
print "Volts Phase B to Neutral: ",
|
||||
print sensor.getVoltsPhaseBToNeutral()
|
||||
print "Volts Phase C to Neutral: ",
|
||||
print sensor.getVoltsPhaseCToNeutral()
|
||||
|
||||
print "Current Phase A:", sensor.getCurrentPhaseA()
|
||||
print "Current Phase B:", sensor.getCurrentPhaseB()
|
||||
print "Current Phase C:", sensor.getCurrentPhaseC()
|
||||
|
||||
print "Avg Real Power (kW):", sensor.getAvgRealPower()
|
||||
print "Min Real Power (kW):", sensor.getMinRealPower()
|
||||
print "Max Real Power (kW):", sensor.getMaxRealPower()
|
||||
|
||||
print
|
||||
time.sleep(2)
|
24
src/h803x/CMakeLists.txt
Normal file
24
src/h803x/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
set (libname "h803x")
|
||||
set (libdescription "upm module for the Veris H803X (H8035/H8036)")
|
||||
set (module_src ${libname}.cxx)
|
||||
set (module_h ${libname}.h)
|
||||
|
||||
pkg_search_module(MODBUS libmodbus)
|
||||
if (MODBUS_FOUND)
|
||||
set (reqlibname "libmodbus")
|
||||
include_directories(${MODBUS_INCLUDE_DIRS})
|
||||
upm_module_init()
|
||||
add_dependencies(${libname} ${MODBUS_LIBRARIES})
|
||||
target_link_libraries(${libname} ${MODBUS_LIBRARIES})
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGNODE)
|
||||
swig_link_libraries (jsupm_${libname} ${MODBUS_LIBRARIES} ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGPYTHON)
|
||||
swig_link_libraries (pyupm_${libname} ${MODBUS_LIBRARIES} ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGJAVA)
|
||||
swig_link_libraries (javaupm_${libname} ${MODBUS_LIBRARIES} ${MRAAJAVA_LDFLAGS} ${JAVA_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
356
src/h803x/h803x.cxx
Normal file
356
src/h803x/h803x.cxx
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "h803x.h"
|
||||
|
||||
using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
// We can't use the modbus float conversion functions since they
|
||||
// assume the first word is the LSW. On this device, the first word
|
||||
// is MSW. In addition, the data is already IEEE 754 formatted, which
|
||||
// won't work with just the bit shuffling modbus_get_float*() does.
|
||||
static float regs2float(uint16_t h, uint16_t l)
|
||||
{
|
||||
// this function will fail horribly if the following isn't true
|
||||
assert(sizeof(float) == sizeof(uint32_t));
|
||||
|
||||
// we can't use a cast here, since the data is already IEEE 754
|
||||
// formatted, so use a union instead.
|
||||
union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} converter;
|
||||
|
||||
converter.i = ((uint32_t)h << 16) | l;
|
||||
return converter.f;
|
||||
}
|
||||
|
||||
|
||||
H803X::H803X(std::string device, int address, int baud, int bits, char parity,
|
||||
int stopBits) :
|
||||
m_mbContext(0)
|
||||
{
|
||||
// check some of the parameters
|
||||
if (!(bits == 7 || bits == 8))
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": bits must be 7 or 8");
|
||||
}
|
||||
|
||||
if (!(parity == 'N' || parity == 'E' || parity == 'O'))
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": parity must be 'N', 'O', or 'E'");
|
||||
}
|
||||
|
||||
if (!(stopBits == 1 || stopBits == 2))
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": stopBits must be 1 or 2");
|
||||
}
|
||||
|
||||
// now, open/init the device and modbus context
|
||||
|
||||
if (!(m_mbContext = modbus_new_rtu(device.c_str(), baud, parity, bits,
|
||||
stopBits)))
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_new_rtu() failed");
|
||||
}
|
||||
|
||||
// set the slave address of the device we want to talk to
|
||||
|
||||
// addresses are only 8bits wide
|
||||
address &= 0xff;
|
||||
if (modbus_set_slave(m_mbContext, address))
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_set_slave() failed");
|
||||
}
|
||||
|
||||
// set the serial mode
|
||||
modbus_rtu_set_serial_mode(m_mbContext, MODBUS_RTU_RS232);
|
||||
|
||||
// now connect..
|
||||
if (modbus_connect(m_mbContext))
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_connect() failed");
|
||||
}
|
||||
|
||||
// will set m_isH8036 appropriately
|
||||
testH8036();
|
||||
|
||||
clearData();
|
||||
|
||||
// turn off debugging
|
||||
setDebug(false);
|
||||
}
|
||||
|
||||
H803X::~H803X()
|
||||
{
|
||||
if (m_mbContext)
|
||||
{
|
||||
modbus_close(m_mbContext);
|
||||
modbus_free(m_mbContext);
|
||||
}
|
||||
}
|
||||
|
||||
int H803X::readHoldingRegs(HOLDING_REGS_T reg, int len, uint16_t *buf)
|
||||
{
|
||||
int rv;
|
||||
int retries = 5;
|
||||
|
||||
// Sometimes it seems the device goes to sleep, and therefore a read
|
||||
// will timeout, so we will retry up to 5 times.
|
||||
|
||||
while (retries >= 0)
|
||||
{
|
||||
if ((rv = modbus_read_registers(m_mbContext, reg, len, buf)) < 0)
|
||||
{
|
||||
if (errno == ETIMEDOUT)
|
||||
{
|
||||
// timeout
|
||||
retries--;
|
||||
sleep(1);
|
||||
}
|
||||
else if (errno == EMBXILADD)
|
||||
{
|
||||
// invalid registers will return a EMBXILADD (modbus)
|
||||
// error. We want to detect these as a way to determine
|
||||
// whether we are dealing with an H8035 or H8036.
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// anything else is a failure.
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_read_registers() failed: "
|
||||
+ modbus_strerror(errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
return rv; // success
|
||||
}
|
||||
|
||||
// if we're here, then all the retries were exhausted
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_read_registers() timed out after "
|
||||
+ "5 retries");
|
||||
}
|
||||
|
||||
void H803X::writeHoldingReg(HOLDING_REGS_T reg, int value)
|
||||
{
|
||||
if (modbus_write_register(m_mbContext, reg, value) != 1)
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_write_register() failed: "
|
||||
+ modbus_strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void H803X::update()
|
||||
{
|
||||
static const int h8035NumRegs = 4; // 2 regs * 2
|
||||
static const int h8036NumRegs = 52; // 26 regs * 2
|
||||
|
||||
int numRegs = (isH8036() ? h8036NumRegs : h8035NumRegs);
|
||||
|
||||
uint16_t buf[numRegs];
|
||||
|
||||
// This should only fail (return -1) if we got isH8036() wrong
|
||||
if (readHoldingRegs(HOLDING_CONSUMPTION_KWH, numRegs, buf) < 0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": readHoldingRegs() failed: "
|
||||
+ modbus_strerror(errno));
|
||||
}
|
||||
|
||||
// And so it begins...
|
||||
|
||||
// H8035 / H8036
|
||||
m_consumptionkWh = regs2float(buf[0], buf[1]);
|
||||
m_realPowerkW = regs2float(buf[2], buf[3]);
|
||||
|
||||
// H8036 only
|
||||
if (isH8036())
|
||||
{
|
||||
m_reactivePowerkVAR = regs2float(buf[4], buf[5]);
|
||||
m_apparentPowerkVA = regs2float(buf[6], buf[7]);
|
||||
m_powerFactor = regs2float(buf[8], buf[9]);
|
||||
|
||||
m_voltsLineToLine = regs2float(buf[10], buf[11]);
|
||||
m_voltsLineToNeutral = regs2float(buf[12], buf[13]);
|
||||
|
||||
m_current = regs2float(buf[14], buf[15]);
|
||||
|
||||
m_realPowerPhaseAkW = regs2float(buf[16], buf[17]);
|
||||
m_realPowerPhaseBkW = regs2float(buf[18], buf[19]);
|
||||
m_realPowerPhaseCkW = regs2float(buf[20], buf[21]);
|
||||
|
||||
m_powerFactorPhaseA = regs2float(buf[22], buf[23]);
|
||||
m_powerFactorPhaseB = regs2float(buf[24], buf[25]);
|
||||
m_powerFactorPhaseC = regs2float(buf[26], buf[27]);
|
||||
|
||||
m_voltsPhaseAB = regs2float(buf[28], buf[29]);
|
||||
m_voltsPhaseBC = regs2float(buf[30], buf[31]);
|
||||
m_voltsPhaseAC = regs2float(buf[32], buf[33]);
|
||||
m_voltsPhaseAN = regs2float(buf[34], buf[35]);
|
||||
m_voltsPhaseBN = regs2float(buf[36], buf[37]);
|
||||
m_voltsPhaseCN = regs2float(buf[38], buf[39]);
|
||||
|
||||
m_currentPhaseA = regs2float(buf[40], buf[41]);
|
||||
m_currentPhaseB = regs2float(buf[42], buf[43]);
|
||||
m_currentPhaseC = regs2float(buf[44], buf[45]);
|
||||
|
||||
m_avgRealPowerkW = regs2float(buf[46], buf[47]);
|
||||
m_minRealPowerkW = regs2float(buf[48], buf[49]);
|
||||
m_maxRealPowerkW = regs2float(buf[50], buf[51]);
|
||||
}
|
||||
}
|
||||
|
||||
string H803X::getSlaveID()
|
||||
{
|
||||
uint8_t id[MODBUS_MAX_PDU_LENGTH];
|
||||
int rv;
|
||||
|
||||
if ((rv = modbus_report_slave_id(m_mbContext, MODBUS_MAX_PDU_LENGTH, id)) < 0)
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_report_slave_id() failed: "
|
||||
+ modbus_strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
// the first byte is the number of bytes in the response, the second
|
||||
// byte is the active indicator (00 = off, ff = on), and the rest
|
||||
// are ascii identification (company, model, and serial number) data.
|
||||
|
||||
if (rv > 2)
|
||||
{
|
||||
string retID((char *)&id[2], rv - 2);
|
||||
return retID;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
void H803X::setSlaveAddress(int addr)
|
||||
{
|
||||
// addresses are only 8bits wide
|
||||
addr &= 0xff;
|
||||
|
||||
if (modbus_set_slave(m_mbContext, addr))
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__)
|
||||
+ ": modbus_set_slave() failed: "
|
||||
+ modbus_strerror(errno));
|
||||
}
|
||||
|
||||
// retest H8036
|
||||
testH8036();
|
||||
|
||||
// clear out any previously stored data
|
||||
clearData();
|
||||
}
|
||||
|
||||
void H803X::setDebug(bool enable)
|
||||
{
|
||||
m_debugging = enable;
|
||||
|
||||
if (enable)
|
||||
modbus_set_debug(m_mbContext, 1);
|
||||
else
|
||||
modbus_set_debug(m_mbContext, 0);
|
||||
}
|
||||
|
||||
void H803X::clearData()
|
||||
{
|
||||
// H8035
|
||||
m_consumptionkWh = 0.0;
|
||||
m_realPowerkW = 0.0;
|
||||
|
||||
// H8036
|
||||
m_reactivePowerkVAR = 0.0;
|
||||
m_apparentPowerkVA = 0.0;
|
||||
m_powerFactor = 0.0;
|
||||
m_voltsLineToLine = 0.0;
|
||||
m_voltsLineToNeutral = 0.0;
|
||||
m_current = 0.0;
|
||||
m_realPowerPhaseAkW = 0.0;
|
||||
m_realPowerPhaseBkW = 0.0;
|
||||
m_realPowerPhaseCkW = 0.0;
|
||||
m_powerFactorPhaseA = 0.0;
|
||||
m_powerFactorPhaseB = 0.0;
|
||||
m_powerFactorPhaseC = 0.0;
|
||||
m_voltsPhaseAB = 0.0;
|
||||
m_voltsPhaseBC = 0.0;
|
||||
m_voltsPhaseAC = 0.0;
|
||||
m_voltsPhaseAN = 0.0;
|
||||
m_voltsPhaseBN = 0.0;
|
||||
m_voltsPhaseCN = 0.0;
|
||||
m_currentPhaseA = 0.0;
|
||||
m_currentPhaseB = 0.0;
|
||||
m_currentPhaseC = 0.0;
|
||||
m_avgRealPowerkW = 0.0;
|
||||
m_minRealPowerkW = 0.0;
|
||||
m_maxRealPowerkW = 0.0;
|
||||
}
|
||||
|
||||
void H803X::testH8036()
|
||||
{
|
||||
// here we test a register read to see if we are on an H8036 device,
|
||||
// which can provide much more information.
|
||||
|
||||
uint16_t regs[2];
|
||||
|
||||
// here, we'll read 2 registers that only exist on the H8036. Any
|
||||
// failure other than a illegal data access will generate an
|
||||
// exception. A valid request will return >0, and an illegal
|
||||
// register read will return -1.
|
||||
if (readHoldingRegs(HOLDING_REACTIVE_POWER_KVAR, 2, regs) == -1)
|
||||
m_isH8036 = false;
|
||||
else
|
||||
m_isH8036 = true;
|
||||
}
|
||||
|
||||
void H803X::presetConsumption(float value, MULTIPLIERS_T multiplier)
|
||||
{
|
||||
uint32_t i = uint32_t(value * float(multiplier));
|
||||
|
||||
uint16_t h = uint16_t(i >> 16);
|
||||
uint16_t l = uint16_t(i & 0xffff);
|
||||
|
||||
// always write the LSW first
|
||||
writeHoldingReg(HOLDING_CONSUMPTION_KWH_INT_L, l);
|
||||
writeHoldingReg(HOLDING_CONSUMPTION_KWH_INT_H, h);
|
||||
}
|
547
src/h803x/h803x.h
Normal file
547
src/h803x/h803x.h
Normal file
@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <modbus/modbus.h>
|
||||
|
||||
namespace upm {
|
||||
|
||||
/**
|
||||
* @brief H803X Energy Meter
|
||||
* @defgroup h803x libupm-h803x
|
||||
* @ingroup uart electric
|
||||
*/
|
||||
|
||||
/**
|
||||
* @library h803x
|
||||
* @sensor h803x
|
||||
* @comname UPM API for the Veris H803X Energy Meter
|
||||
* @type electic
|
||||
* @man veris
|
||||
* @con uart
|
||||
* @web http://www.veris.com/Item/H8035-0100-2.aspx
|
||||
*
|
||||
* @brief UPM API for the Veris H803X Energy Meter
|
||||
*
|
||||
* This module implements support for the Veris H8035 and H8036
|
||||
* Energy Meters.
|
||||
*
|
||||
* The H8036 is similar to the H8035, but provides much more data.
|
||||
*
|
||||
* The Enercept H8035/H8036 is an innovative three-phase networked
|
||||
* (Modbus RTU) power transducer that combines electronics and high
|
||||
* accuracy industrial grade CTs in a single package. The need for
|
||||
* external electrical enclosures is eliminated, greatly reducing
|
||||
* installation time and cost. Color-coordination between voltage
|
||||
* leads and CTs makes phase matching easy. Additionally, these
|
||||
* transducers automatically detect and compensate for phase
|
||||
* reversal, eliminating the concern of CT load orientation. Up to
|
||||
* 63 Transducers can be daisy-chained on a single RS-485 network.
|
||||
*
|
||||
* This module was developed using libmodbus 3.1.2, and the H8035.
|
||||
* The H8036 has not been tested. libmodbus 3.1.2 must be present
|
||||
* for this module to build.
|
||||
*
|
||||
* It was developed using an RS232->RS485 interface. You cannot use
|
||||
* the built in MCU TTL UART pins for accessing this device -- you
|
||||
* must use a full Serial RS232->RS485 or USB-RS485 interface
|
||||
* connected via USB.
|
||||
*
|
||||
* @snippet h803x.cxx Interesting
|
||||
*/
|
||||
|
||||
class H803X {
|
||||
public:
|
||||
|
||||
// MODBUS holding registers. These offsets are for the MSW only.
|
||||
// The LSW always follows, though they are not enumerated here.
|
||||
// These are all 2 register (32-bit total (16b HSW + 16b LSW))
|
||||
// quantities, in IEEE 754 floating point format.
|
||||
typedef enum {
|
||||
// these two registers are used only for presetConsumption()
|
||||
HOLDING_CONSUMPTION_KWH_INT_L = 0, // preset use only
|
||||
HOLDING_CONSUMPTION_KWH_INT_H = 1, // preset use only
|
||||
|
||||
// H8035/H8036
|
||||
HOLDING_CONSUMPTION_KWH = 258, // floating point data
|
||||
|
||||
HOLDING_REAL_POWER_KW = 260,
|
||||
|
||||
// H8036 only
|
||||
HOLDING_REACTIVE_POWER_KVAR = 262,
|
||||
HOLDING_APPARENT_POWER_KVA = 264,
|
||||
HOLDING_POWER_FACTOR = 266,
|
||||
HOLDING_VOLTS_LINE_TO_LINE = 268,
|
||||
HOLDING_VOLTS_LINE_TO_NEUTRAL = 270,
|
||||
HOLDING_CURRENT = 272,
|
||||
HOLDING_REAL_POWER_PHASE_A_KWH = 274,
|
||||
HOLDING_REAL_POWER_PHASE_B_KWH = 276,
|
||||
HOLDING_REAL_POWER_PHASE_C_KWH = 278,
|
||||
HOLDING_POWER_FACTOR_PHASE_A = 280,
|
||||
HOLDING_POWER_FACTOR_PHASE_B = 282,
|
||||
HOLDING_POWER_FACTOR_PHASE_C = 284,
|
||||
HOLDING_VOLTS_PHASE_AB = 286,
|
||||
HOLDING_VOLTS_PHASE_BC = 288,
|
||||
HOLDING_VOLTS_PHASE_AC = 290,
|
||||
HOLDING_VOLTS_PHASE_AN = 292,
|
||||
HOLDING_VOLTS_PHASE_BN = 294,
|
||||
HOLDING_VOLTS_PHASE_CN = 296,
|
||||
HOLDING_CURRENT_PHASE_A = 298,
|
||||
HOLDING_CURRENT_PHASE_B = 300,
|
||||
HOLDING_CURRENT_PHASE_C = 302,
|
||||
HOLDING_AVG_REAL_POWER_KW = 304,
|
||||
HOLDING_MIN_REAL_POWER_KW = 306,
|
||||
HOLDING_MAX_REAL_POWER_KW = 308
|
||||
} HOLDING_REGS_T;
|
||||
|
||||
// these enums are used by presetConsumption() to scale the value
|
||||
// properly depending on the devices' current capacity.
|
||||
typedef enum {
|
||||
MULT_100A = 128, // 100A devices
|
||||
MULT_300A_400A = 32,
|
||||
MULT_800A = 16,
|
||||
MULT_1600A = 8,
|
||||
MULT_2400A = 4
|
||||
} MULTIPLIERS_T;
|
||||
|
||||
/**
|
||||
* H803X constructor
|
||||
*
|
||||
* @param device Path to the serial device
|
||||
* @param address The MODBUS slave address
|
||||
* @param baud The baudrate of the device. Default: 9600
|
||||
* @param bits The number of bits per byte. Default: 8
|
||||
* @param parity The parity of the connection, 'N' for None, 'E'
|
||||
* for Even, 'O' for Odd. Default: 'N'
|
||||
* @param stopBits The number of stop bits. Default: 2
|
||||
*/
|
||||
H803X(std::string device, int address, int baud=9600, int bits=8,
|
||||
char parity='N', int stopBits=2);
|
||||
|
||||
/**
|
||||
* H803X Destructor
|
||||
*/
|
||||
~H803X();
|
||||
|
||||
/**
|
||||
* Read current values from the sensor and update internal stored
|
||||
* values. This method must be called prior to querying any
|
||||
* values.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Return a string corresponding the the device's MODBUS slave ID.
|
||||
*
|
||||
* @return string represnting the MODBUS slave ID
|
||||
*/
|
||||
std::string getSlaveID();
|
||||
|
||||
/**
|
||||
* Set a new MODBUS slave address. This is useful if you have
|
||||
* multiple H803X devices on a single bus. When this method is
|
||||
* called, the current stored data is cleared, and a new attempt
|
||||
* is made to determine whether the target device is an H8035 or
|
||||
* H8036.
|
||||
*
|
||||
* @param addr The new slave address to set
|
||||
*/
|
||||
void setSlaveAddress(int addr);
|
||||
|
||||
/**
|
||||
* Preset the kWh accumulated Consumption registers to a
|
||||
* predefined value. This is generally not advised, but is
|
||||
* provided for those installations that might require it. The
|
||||
* multiplier depends on the current range of your device. Be
|
||||
* sure to select the right multiplier for your devices'
|
||||
* supported current capacity.
|
||||
*
|
||||
* @param value The desired value for the consumption accumulator
|
||||
* registers in kWh.
|
||||
* @param multiplier The correct MULTIPLIERS_T value for your device.
|
||||
*/
|
||||
void presetConsumption(float value, MULTIPLIERS_T multiplier);
|
||||
|
||||
/**
|
||||
* Return the accumulated consumption value, in kWh. update() must
|
||||
* have been called prior to calling this method.
|
||||
*
|
||||
* @return The accumulated consumption.
|
||||
*/
|
||||
float getConsumption()
|
||||
{
|
||||
return m_consumptionkWh;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the real power value in kW. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The real power value in kW.
|
||||
*/
|
||||
float getRealPower()
|
||||
{
|
||||
return m_realPowerkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the reactive power value in kVAR (kilo-volt Amperes
|
||||
* Reactive). update() must have been called prior to calling this
|
||||
* method.
|
||||
*
|
||||
* @return The reactive power value in kVAR.
|
||||
*/
|
||||
float getReactivePower()
|
||||
{
|
||||
return m_reactivePowerkVAR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the apparent power value in kVA. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The apparent power value in kVA.
|
||||
*/
|
||||
float getApparentPower()
|
||||
{
|
||||
return m_apparentPowerkVA;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the power factor value. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The power factor.
|
||||
*/
|
||||
float getPowerFactor()
|
||||
{
|
||||
return m_powerFactor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage line to line value. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The voltage, line to line.
|
||||
*/
|
||||
float getVoltsLineToLine()
|
||||
{
|
||||
return m_voltsLineToLine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage line to neutral. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The voltage, line to neutral.
|
||||
*/
|
||||
float getVoltsLineToNeutral()
|
||||
{
|
||||
return m_voltsLineToNeutral;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current value in amps. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The current value in amps.
|
||||
*/
|
||||
float getCurrent()
|
||||
{
|
||||
return m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the real power for phase A. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The real power for phase A.
|
||||
*/
|
||||
float getRealPowerPhaseA()
|
||||
{
|
||||
return m_realPowerPhaseAkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the real power for phase B. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The real power for phase B.
|
||||
*/
|
||||
float getRealPowerPhaseB()
|
||||
{
|
||||
return m_realPowerPhaseBkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the real power for phase C. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The real power for phase C.
|
||||
*/
|
||||
float getRealPowerPhaseC()
|
||||
{
|
||||
return m_realPowerPhaseCkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the power factor for phase A. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The power factor for phase A.
|
||||
*/
|
||||
float getPowerFactorPhaseA()
|
||||
{
|
||||
return m_powerFactorPhaseA;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the power factor for phase B. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The power factor for phase B.
|
||||
*/
|
||||
float getPowerFactorPhaseB()
|
||||
{
|
||||
return m_powerFactorPhaseB;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the power factor for phase C. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The power factor for phase C.
|
||||
*/
|
||||
float getPowerFactorPhaseC()
|
||||
{
|
||||
return m_powerFactorPhaseC;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase A to B. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase A to B.
|
||||
*/
|
||||
float getVoltsPhaseAToB()
|
||||
{
|
||||
return m_voltsPhaseAB;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase B to C. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase B to C.
|
||||
*/
|
||||
float getVoltsPhaseBToC()
|
||||
{
|
||||
return m_voltsPhaseBC;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase A to B. update() must have been
|
||||
* called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase A to B.
|
||||
*/
|
||||
float getVoltsPhaseAToC()
|
||||
{
|
||||
return m_voltsPhaseAC;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase A to neutral. update() must have
|
||||
* been called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase A to neutral.
|
||||
*/
|
||||
float getVoltsPhaseAToNeutral()
|
||||
{
|
||||
return m_voltsPhaseAN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase B to neutral. update() must have
|
||||
* been called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase B to neutral.
|
||||
*/
|
||||
float getVoltsPhaseBToNeutral()
|
||||
{
|
||||
return m_voltsPhaseBN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the voltage for phase C to neutral. update() must have
|
||||
* been called prior to calling this method.
|
||||
*
|
||||
* @return The voltage for phase C to neutral.
|
||||
*/
|
||||
float getVoltsPhaseCToNeutral()
|
||||
{
|
||||
return m_voltsPhaseCN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current for phase A. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The current for phase A.
|
||||
*/
|
||||
float getCurrentPhaseA()
|
||||
{
|
||||
return m_currentPhaseA;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current for phase B. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The current for phase B.
|
||||
*/
|
||||
float getCurrentPhaseB()
|
||||
{
|
||||
return m_currentPhaseB;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current for phase C. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The current for phase C.
|
||||
*/
|
||||
float getCurrentPhaseC()
|
||||
{
|
||||
return m_currentPhaseC;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the average real power. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The average real power.
|
||||
*/
|
||||
float getAvgRealPower()
|
||||
{
|
||||
return m_avgRealPowerkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the minimum real power. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The minimum real power.
|
||||
*/
|
||||
float getMinRealPower()
|
||||
{
|
||||
return m_minRealPowerkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the maximum real power. update() must have been called
|
||||
* prior to calling this method.
|
||||
*
|
||||
* @return The maximum real power.
|
||||
*/
|
||||
float getMaxRealPower()
|
||||
{
|
||||
return m_maxRealPowerkW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable debugging output. This primarily enables and
|
||||
* disables libmodbus debugging output.
|
||||
*
|
||||
* @param enable true to enable debugging, false otherwise
|
||||
*/
|
||||
void setDebug(bool enable);
|
||||
|
||||
/**
|
||||
* Indicate whether the connected device is an H8035 or an H8036.
|
||||
* The H8036 provides many more data registers.
|
||||
*
|
||||
* @return true if we are using an H8036, false otherwise.
|
||||
*/
|
||||
bool isH8036()
|
||||
{
|
||||
return m_isH8036;
|
||||
};
|
||||
|
||||
protected:
|
||||
// holding registers
|
||||
int readHoldingRegs(HOLDING_REGS_T reg, int len, uint16_t *buf);
|
||||
void writeHoldingReg(HOLDING_REGS_T reg, int value);
|
||||
|
||||
// clear out all stored data
|
||||
void clearData();
|
||||
|
||||
// MODBUS context
|
||||
modbus_t *m_mbContext;
|
||||
|
||||
// test to see if the connected device is an H8036, and set
|
||||
// m_isH8036 appropriately
|
||||
void testH8036();
|
||||
|
||||
// Is this an H8036 (has extended registers)
|
||||
bool m_isH8036;
|
||||
|
||||
private:
|
||||
bool m_debugging;
|
||||
|
||||
// data
|
||||
|
||||
// H8035 / H8036
|
||||
float m_consumptionkWh;
|
||||
float m_realPowerkW;
|
||||
|
||||
// H8036 only
|
||||
float m_reactivePowerkVAR;
|
||||
float m_apparentPowerkVA;
|
||||
float m_powerFactor;
|
||||
float m_voltsLineToLine;
|
||||
float m_voltsLineToNeutral;
|
||||
float m_current; // in amps
|
||||
float m_realPowerPhaseAkW;
|
||||
float m_realPowerPhaseBkW;
|
||||
float m_realPowerPhaseCkW;
|
||||
float m_powerFactorPhaseA;
|
||||
float m_powerFactorPhaseB;
|
||||
float m_powerFactorPhaseC;
|
||||
float m_voltsPhaseAB;
|
||||
float m_voltsPhaseBC;
|
||||
float m_voltsPhaseAC;
|
||||
float m_voltsPhaseAN;
|
||||
float m_voltsPhaseBN;
|
||||
float m_voltsPhaseCN;
|
||||
float m_currentPhaseA;
|
||||
float m_currentPhaseB;
|
||||
float m_currentPhaseC;
|
||||
float m_avgRealPowerkW;
|
||||
float m_minRealPowerkW;
|
||||
float m_maxRealPowerkW;
|
||||
};
|
||||
}
|
20
src/h803x/javaupm_h803x.i
Normal file
20
src/h803x/javaupm_h803x.i
Normal file
@ -0,0 +1,20 @@
|
||||
%module javaupm_h803x
|
||||
%include "../upm.i"
|
||||
%include "typemaps.i"
|
||||
|
||||
%{
|
||||
#include "h803x.h"
|
||||
%}
|
||||
|
||||
%include "h803x.h"
|
||||
|
||||
%pragma(java) jniclasscode=%{
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_h803x");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("Native code library failed to load. \n" + e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
%}
|
8
src/h803x/jsupm_h803x.i
Normal file
8
src/h803x/jsupm_h803x.i
Normal file
@ -0,0 +1,8 @@
|
||||
%module jsupm_h803x
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
|
||||
%include "h803x.h"
|
||||
%{
|
||||
#include "h803x.h"
|
||||
%}
|
12
src/h803x/pyupm_h803x.i
Normal file
12
src/h803x/pyupm_h803x.i
Normal file
@ -0,0 +1,12 @@
|
||||
// Include doxygen-generated documentation
|
||||
%include "pyupm_doxy2swig.i"
|
||||
%module pyupm_h803x
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
|
||||
%feature("autodoc", "3");
|
||||
|
||||
%include "h803x.h"
|
||||
%{
|
||||
#include "h803x.h"
|
||||
%}
|
Loading…
x
Reference in New Issue
Block a user