From 3c5d498ae58d2872c34c61c40f8000f5c27027d9 Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Fri, 10 Jun 2016 12:46:49 -0600 Subject: [PATCH] t8100: Initial implementation This module implements support for the Amphenol Telaire Ventostat T8100 Ventilation Controller with BACnet interface. It may also support the T8200 and T8300 models, but they have not been tested. The Telaire Ventostat T8100 reports Temperature, Humidity and CO2 concentrations. It supports an optional relay with a settable trigger point. The unit this driver was tested under did not support the optional relay. The temperature range supported is 0-50C, humidity is 0-100% non-condensing, and CO2 range is appoximately 0-2000 PPM for the T8100. Other sensors in this family support wider ranges. Signed-off-by: Jon Trulson --- examples/c++/CMakeLists.txt | 1 + examples/c++/t8100.cxx | 117 ++++++++++ examples/java/CMakeLists.txt | 1 + examples/java/T8100_Example.java | 97 ++++++++ examples/javascript/t8100.js | 98 ++++++++ examples/python/t8100.py | 97 ++++++++ src/t8100/CMakeLists.txt | 28 +++ src/t8100/javaupm_t8100.i | 22 ++ src/t8100/jsupm_t8100.i | 10 + src/t8100/pyupm_t8100.i | 14 ++ src/t8100/t8100.cxx | 254 +++++++++++++++++++++ src/t8100/t8100.hpp | 379 +++++++++++++++++++++++++++++++ 12 files changed, 1118 insertions(+) create mode 100644 examples/c++/t8100.cxx create mode 100644 examples/java/T8100_Example.java create mode 100644 examples/javascript/t8100.js create mode 100644 examples/python/t8100.py create mode 100644 src/t8100/CMakeLists.txt create mode 100644 src/t8100/javaupm_t8100.i create mode 100644 src/t8100/jsupm_t8100.i create mode 100644 src/t8100/pyupm_t8100.i create mode 100644 src/t8100/t8100.cxx create mode 100644 src/t8100/t8100.hpp diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 524ec973..7d380310 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -262,6 +262,7 @@ if (BACNET_FOUND) # we need access to bacnetmstp headers too include_directories(${PROJECT_SOURCE_DIR}/src/bacnetmstp) add_example (e50hx) + add_example (t8100) endif() add_example (vcap) add_example (ds2413) diff --git a/examples/c++/t8100.cxx b/examples/c++/t8100.cxx new file mode 100644 index 00000000..3cecbac4 --- /dev/null +++ b/examples/c++/t8100.cxx @@ -0,0 +1,117 @@ +/* + * Author: Jon Trulson + * 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 +#include +#include + +#include "t8100.hpp" + +using namespace std; +using namespace upm; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + // You will need to edit this example to conform to your site and your + // devices, specifically the Device Object Instance ID passed to the + // constructor, and the arguments to initMaster() that are + // appropriate for your BACnet network. + + 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 T8100 object for an T8100 device that has 568000 + // as it's unique Device Object Instance ID. NOTE: You will + // certainly want to change this to the correct value for your + // device(s). + T8100 *sensor = new T8100(568000); + + // Initialize our BACnet master, if it has not already been + // initialized, with the device and baudrate, choosing 1000001 as + // our unique Device Object Instance ID, 2 as our MAC address and + // using default values for maxMaster and maxInfoFrames + sensor->initMaster(defaultDev, 38400, 1000001, 2); + + // Uncomment to enable debugging output + // sensor->setDebug(true); + + cout << endl; + cout << "Device Description: " << sensor->getDeviceDescription() << endl; + cout << "Device Location: " << sensor->getDeviceLocation() << endl; + cout << endl; + + // update and print a few values every 5 seconds + while (shouldRun) + { + // update our values + sensor->update(); + + cout << "CO2 Concentration: " + << sensor->getCO2() + << " ppm" + << endl; + + // we show both C and F for temperature + cout << "Temperature: " << sensor->getTemperature() + << " C / " + << sensor->getTemperature(true) + << " F" + << endl; + + cout << "Humidity: " << sensor->getHumidity() + << " %RH" + << endl; + + cout << "Relay State: " << sensor->getRelayState() + << endl; + + cout << endl; + sleep(5); + } + + cout << "Exiting..." << endl; + + delete sensor; + +//! [Interesting] + + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index 7a6bf615..b1ee421e 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -124,6 +124,7 @@ if (MODBUS_FOUND) endif() if (BACNET_FOUND) add_example(E50HX_Example e50hx) + add_example(T8100_Example t8100) endif() add_example(VCAP_Example vcap) add_example(BMP280_Example bmp280) diff --git a/examples/java/T8100_Example.java b/examples/java/T8100_Example.java new file mode 100644 index 00000000..162c23f7 --- /dev/null +++ b/examples/java/T8100_Example.java @@ -0,0 +1,97 @@ +/* + * Author: Jon Trulson + * 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_t8100.T8100; + +public class T8100_Example +{ + private static String defaultDev = "/dev/ttyUSB0"; + + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + + // You will need to edit this example to conform to your site + // and your devices, specifically the Device Object Instance + // ID passed to the constructor, and the arguments to + // initMaster() that are appropriate for your BACnet network. + + if (args.length > 0) + defaultDev = args[0]; + System.out.println("Using device " + defaultDev); + System.out.println("Initializing..."); + + // Instantiate an T8100 object for an T8100 device that has + // 568000 as it's unique Device Object Instance ID. NOTE: You + // will certainly want to change this to the correct value for + // your device(s). + T8100 sensor = new T8100(568000); + + // Initialize our BACnet master, if it has not already been + // initialized, with the device and baudrate, choosing 1000001 + // as our unique Device Object Instance ID, 2 as our MAC + // address and using default values for maxMaster and + // maxInfoFrames + sensor.initMaster(defaultDev, 38400, 1000001, 2); + + // Uncomment to enable debugging output + // sensor.setDebug(true); + + System.out.println(); + System.out.println("Device Description: " + + sensor.getDeviceDescription()); + System.out.println("Device Location: " + sensor.getDeviceLocation()); + System.out.println(); + + // update and print a few values every 5 seconds + while (true) + { + // update our values + sensor.update(); + + System.out.println("CO2 Concentration: " + + sensor.getCO2() + + " ppm"); + + // we show both C and F for temperature + System.out.println("Temperature: " + + sensor.getTemperature() + + " C / " + + sensor.getTemperature(true) + + " F"); + + System.out.println("Humidity: " + + sensor.getHumidity() + + " %RH"); + + System.out.println("Relay State: " + + sensor.getRelayState()); + + System.out.println(); + Thread.sleep(5000); + } + +// ! [Interesting] + } +} diff --git a/examples/javascript/t8100.js b/examples/javascript/t8100.js new file mode 100644 index 00000000..7be2fad6 --- /dev/null +++ b/examples/javascript/t8100.js @@ -0,0 +1,98 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* + * Author: Jon Trulson + * 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_t8100'); + + +/************** Main code **************/ + +// You will need to edit this example to conform to your site and your +// devices, specifically the Device Object Instance ID passed to the +// constructor, and the arguments to initMaster() that are +// appropriate for your BACnet network. + +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 T8100 object for an T8100 device that has 568000 +// as it's unique Device Object Instance ID. NOTE: You will +// certainly want to change this to the correct value for your +// device(s). +var sensor = new sensorObj.T8100(568000); + +// Initialize our BACnet master, if it has not already been +// initialized, with the device and baudrate, choosing 1000001 as +// our unique Device Object Instance ID, 2 as our MAC address and +// using default values for maxMaster and maxInfoFrames +sensor.initMaster(defaultDev, 38400, 1000001, 2); + +// Uncomment to enable debugging output +// sensor.setDebug(true); + +console.log(""); +console.log("Device Description:", sensor.getDeviceDescription()); +console.log("Device Location:", sensor.getDeviceLocation()); +console.log(""); + +// update and print a few values every 5 seconds +setInterval(function() +{ + // update our values + sensor.update(); + + console.log("CO2 Concentration:", sensor.getCO2(), "ppm"); + + // we show both C and F for temperature + console.log("Temperature:", sensor.getTemperature(), + "C /", sensor.getTemperature(true), "F"); + + console.log("Humidity:", sensor.getHumidity(), "%RH"); + + console.log("Relay State:", sensor.getRelayState()); + + console.log(""); + +}, 5000); + + +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting..."); + process.exit(0); +}); diff --git a/examples/python/t8100.py b/examples/python/t8100.py new file mode 100644 index 00000000..2f14651d --- /dev/null +++ b/examples/python/t8100.py @@ -0,0 +1,97 @@ +#!/usr/bin/python +# Author: Jon Trulson +# 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_t8100 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) + +# You will need to edit this example to conform to your site and your +# devices, specifically the Device Object Instance ID passed to the +# constructor, and the arguments to initMaster() that are +# appropriate for your BACnet network. + +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 T8100 object for an T8100 device that has 568000 +# as it's unique Device Object Instance ID. NOTE: You will +# certainly want to change this to the correct value for your +# device(s). +sensor = sensorObj.T8100(568000) + +# Initialize our BACnet master, if it has not already been +# initialized, with the device and baudrate, choosing 1000001 as +# our unique Device Object Instance ID, 2 as our MAC address and +# using default values for maxMaster and maxInfoFrames +sensor.initMaster(defaultDev, 38400, 1000001, 2) + +# Uncomment to enable debugging output +# sensor.setDebug(True); + +# output the serial number and firmware revision +print +print "Device Description:", sensor.getDeviceDescription() +print "Device Location:", sensor.getDeviceLocation() +print + +# update and print available values every 5 seconds +while (1): + # update our values + sensor.update(); + + print "CO2 Concentration:", + print sensor.getCO2(), + print "ppm" + + # we show both C and F for temperature + print "Temperature:", sensor.getTemperature(), + print "C /", sensor.getTemperature(True), "F" + + print "Humidity:", + print sensor.getHumidity(), + print "%RH" + + print "Relay State:", + print sensor.getRelayState() + + print + time.sleep(5) diff --git a/src/t8100/CMakeLists.txt b/src/t8100/CMakeLists.txt new file mode 100644 index 00000000..cc68020b --- /dev/null +++ b/src/t8100/CMakeLists.txt @@ -0,0 +1,28 @@ +set (libname "t8100") +set (libdescription "upm module for the Telaire T8100 Ventostat") +set (module_src ${libname}.cxx) +set (module_hpp ${libname}.hpp) + +pkg_check_modules(BACNET libbacnet) +if (BACNET_FOUND) + # upm-libbacnetmstp will bring in libbacnet, I hope + set (reqlibname "upm-bacnetmstp") + include_directories(${BACNET_INCLUDE_DIRS}) + include_directories("../bacnetmstp") + upm_module_init() + target_link_libraries(${libname} bacnetmstp) + if (BUILDSWIG) + if (BUILDSWIGNODE) + set_target_properties(${SWIG_MODULE_jsupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE) + swig_link_libraries (jsupm_${libname} bacnetmstp) + endif() + if (BUILDSWIGPYTHON) + set_target_properties(${SWIG_MODULE_pyupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE) + swig_link_libraries (pyupm_${libname} bacnetmstp) + endif() + if (BUILDSWIGJAVA) + set_target_properties(${SWIG_MODULE_javaupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE) + swig_link_libraries (javaupm_${libname} bacnetmstp) + endif() + endif() +endif () diff --git a/src/t8100/javaupm_t8100.i b/src/t8100/javaupm_t8100.i new file mode 100644 index 00000000..20e9a927 --- /dev/null +++ b/src/t8100/javaupm_t8100.i @@ -0,0 +1,22 @@ +%module javaupm_t8100 +%include "../upm.i" +%include "typemaps.i" + +%include "bacnetmstp.hpp" +%include "bacnetutil.hpp" +%include "t8100.hpp" +%{ + #include "t8100.hpp" +%} + + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_t8100"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/t8100/jsupm_t8100.i b/src/t8100/jsupm_t8100.i new file mode 100644 index 00000000..147dc736 --- /dev/null +++ b/src/t8100/jsupm_t8100.i @@ -0,0 +1,10 @@ +%module jsupm_t8100 +%include "../upm.i" +%include "stdint.i" + +%include "bacnetmstp.hpp" +%include "bacnetutil.hpp" +%include "t8100.hpp" +%{ + #include "t8100.hpp" +%} diff --git a/src/t8100/pyupm_t8100.i b/src/t8100/pyupm_t8100.i new file mode 100644 index 00000000..db003c72 --- /dev/null +++ b/src/t8100/pyupm_t8100.i @@ -0,0 +1,14 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_t8100 +%include "../upm.i" +%include "stdint.i" + +%feature("autodoc", "3"); + +%include "bacnetmstp.hpp" +%include "bacnetutil.hpp" +%include "t8100.hpp" +%{ + #include "t8100.hpp" +%} diff --git a/src/t8100/t8100.cxx b/src/t8100/t8100.cxx new file mode 100644 index 00000000..6e5b596a --- /dev/null +++ b/src/t8100/t8100.cxx @@ -0,0 +1,254 @@ +/* + * Author: Jon Trulson + * 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 +#include +#include +#include +#include +#include + +#include "t8100.hpp" + +using namespace upm; +using namespace std; + +// conversion from fahrenheit to celcius and back + +static float f2c(float f) +{ + return ((f - 32.0) / (9.0 / 5.0)); +} + +static float c2f(float c) +{ + return (c * (9.0 / 5.0) + 32.0); +} + + +T8100::T8100(uint32_t targetDeviceObjectID) : + BACNETUTIL(targetDeviceObjectID) +{ + setDebug(false); + + // we disable this by default for performance reasons + checkReliability(false); + + m_isTempInitialized = false; + m_isCelcius = false; + + m_humidity = 0.0; + m_temperature = 0.0; + m_co2 = 0.0; + m_relayState = false; +} + +T8100::~T8100() +{ +} + +void T8100::update() +{ + if (!m_isTempInitialized) + { + // this will update internals so conversions work properly + getTemperatureScale(); + } + + float tmpF = getAnalogInput(AI_Temperature_Thermistor); + + if (m_isCelcius) + m_temperature = tmpF; + else + m_temperature = f2c(tmpF); + + m_humidity = getAnalogInput(AI_Relative_Humidity); + m_co2 = getAnalogInput(AI_CO2); + m_relayState = getBinaryInput(BI_Relay_State); +} + +float T8100::getTemperature(bool fahrenheit) +{ + if (fahrenheit) + return c2f(m_temperature); + else + return m_temperature; +} + +void T8100::setTemperatureScale(bool fahrenheit) +{ + setBinaryValue(BV_Temperature_Units, fahrenheit); + + m_isTempInitialized = true; + m_isCelcius = (fahrenheit) ? false : true; +} + +bool T8100::getTemperatureScale() +{ + bool scale = getBinaryValue(BV_Temperature_Units); + + m_isTempInitialized = true; + m_isCelcius = !scale; + + return scale; +} + +float T8100::getTemperatureOffset() +{ + return getAnalogValue(AV_Temperature_Offset); +} + +void T8100::setTemperatureOffset(float value) +{ + // Always in C... + if (value < -50.0 || value > 50.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between -50 and 50," + + " in degrees Celcius"); + + } + + setAnalogValue(AV_Temperature_Offset, value); +} + +float T8100::getHumidityOffset() +{ + return getAnalogValue(AV_RH_Offset); +} + +void T8100::setHumidityOffset(float value) +{ + if (value < -100.0 || value > 100.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between -100 and 100"); + } + + setAnalogValue(AV_RH_Offset, value); +} + +float T8100::getRelaySetPoint() +{ + return getAnalogValue(AV_Relay_Set_Point); +} + +void T8100::setRelaySetPoint(float value) +{ + if (value < 0.00 || value > 65535.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between 0 and 65535"); + } + + setAnalogValue(AV_Relay_Set_Point, value); +} + +float T8100::getRelayHysteresis() +{ + return getAnalogValue(AV_Relay_Hysteresis); +} + +void T8100::setRelayHysteresis(float value) +{ + if (value < 0.00 || value > 65535.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between 0 and 65535"); + } + + setAnalogValue(AV_Relay_Hysteresis, value); +} + +float T8100::getElevation() +{ + return getAnalogValue(AV_Elevation); +} + +void T8100::setElevation(float value) +{ + if (value < 0.00 || value > 65535.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between 0 and 65535"); + } + + setAnalogValue(AV_Elevation, value); +} + +float T8100::getCalibrationSinglePoint() +{ + return getAnalogValue(AV_Calibration_Single_Point); +} + +void T8100::setCalibrationSinglePoint(float value) +{ + if (value < 0.00 || value > 65535.0) + { + throw std::out_of_range(std::string(__FUNCTION__) + + ": value must be between 0 and 65535"); + } + + setAnalogValue(AV_Calibration_Single_Point, value); +} + +float T8100::getBaudRate() +{ + return getAnalogValue(AV_Baud_Rate); +} + +float T8100::getMACAddress() +{ + return getAnalogValue(AV_MAC_Address); +} + +bool T8100::getABCLogicState() +{ + return getBinaryValue(BV_ABC_Logic_State); +} + +void T8100::setABCLogicState(bool value) +{ + setBinaryValue(BV_ABC_Logic_State, value); +} + +bool T8100::getABCLogicReset() +{ + return getBinaryValue(BV_ABC_Logic_Reset); +} + +void T8100::setABCLogicReset(bool value) +{ + setBinaryValue(BV_ABC_Logic_Reset, value); +} + +bool T8100::getCO2Calibration() +{ + return getBinaryValue(BV_CO2_Calibration); +} + +void T8100::setCO2Calibration(bool value) +{ + setBinaryValue(BV_CO2_Calibration, value); +} diff --git a/src/t8100/t8100.hpp b/src/t8100/t8100.hpp new file mode 100644 index 00000000..bc53d825 --- /dev/null +++ b/src/t8100/t8100.hpp @@ -0,0 +1,379 @@ +/* + * Author: Jon Trulson + * 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 +#include + +#include "bacnetmstp.hpp" +#include "bacnetutil.hpp" + +namespace upm { + + /** + * @brief Amphenol Telaire Ventostat T8100 Ventilation Controller + * @defgroup t8100 libupm-t8100 + * @ingroup uart temp gaseous + */ + + /** + * @library t8100 + * @sensor t8100 + * @comname UPM API for the Amphenol Telaire Ventostat T8100 + * Ventilation Controller + * @type gaseous temp + * @man amphenol + * @con uart + * @web https://www.instrumart.com/products/configure/18180?quantity=1 + * + * @brief UPM API for the Amphenol Telaire Ventostat T8100 + * Ventilation Controller + * + * This module implements support for the Amphenol Telaire Ventostat + * T8100 Ventilation Controller with BACnet interface. It may also + * support the T8200 and T8300 models, but they have not been + * tested. + * + * The Telaire Ventostat T8100 reports Temperature, Humidity and CO2 + * concentrations. It supports an optional relay with a settable + * trigger point. The unit this driver was tested under did not + * support the optional relay. The temperature range supported is + * 0-50C, humidity is 0-100% non-condensing, and CO2 range is + * appoximately 0-2000 PPM for the T8100. Other sensors in this + * family support wider ranges. + * + * This module was developed using the upm::BACNETMSTP library, + * based on libbacnet-stack 0.8.3. Both libbacnet 0.8.3 and the + * upm::BACNETMSTP libraries must be present in order to build this + * module. + * + * It was connected 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 t8100.cxx Interesting + */ + + class T8100 : public BACNETUTIL { + public: + + // Supported Analog Value Objects. These are readable and writable. + typedef enum : uint32_t { + AV_Temperature_Offset = 1, + AV_RH_Offset = 2, + AV_Relay_Set_Point = 3, + AV_Relay_Hysteresis = 4, + AV_Elevation = 5, + AV_Calibration_Single_Point = 6, + AV_Baud_Rate = 7, + AV_MAC_Address = 8 + } ANALOG_VALUES_T; + + // Supported Analog Input Objects. These are read only. + typedef enum : uint32_t { + AI_CO2 = 1, + AI_Relative_Humidity = 2, + AI_Temperature_ChipCap = 3, + AI_Temperature_Thermistor = 4 + } ANALOG_INPUTS_T; + + // Supported Binary Value Objects. These are readable and writable. + typedef enum : uint32_t { + BV_Temperature_Units = 1, + BV_ABC_Logic_State = 2, + BV_ABC_Logic_Reset = 3, + BV_CO2_Calibration = 4 + } BINARY_VALUES_T; + + // Supported Binary Input Objects. These are read only. + typedef enum : uint32_t { + BI_Relay_State = 1 + } BINARY_INPUTS_T; + + + /** + * T8100 constructor + * + * @param targetDeviceObjectID the unique Instance ID of the + * Device Object. This number is used to uniquely identify + * devices on the BACnet network, and ranges from 1 to 4194302. + * This is not the device's MAC address, though on some devices, + * the MAC address may be used as part of this number. On the + * T8100, this number is 568XXX, where XXX are the 3 digits of the + * set MAC address. The MAC address is configured via DIP switches + * within the device. + */ + T8100(uint32_t targetDeviceObjectID); + + /** + * T8100 Destructor + */ + ~T8100(); + + /** + * Read current values from the sensor and update internal stored + * values for temperature, humidity, CO2 concentration and relay + * state. This method must be called prior to querying any + * of the aforementioned values. + */ + void update(); + + /** + * Get the current relative humidity. update() must have been + * called prior to calling this method. + * + * @return The last humidity reading + */ + float getHumidity() + { + return m_humidity; + } + + /** + * Get the current CO2 concentration in Parts per Million (PPM). + * update() must have been called prior to calling this method. + * + * @return The last CO2 reading + */ + float getCO2() + { + return m_co2; + } + + /** + * Get the current temperature. update() must have been called + * prior to calling this method. + * + * @param fahrenheit true to return the temperature in degrees + * fahrenheit, false to return the temperature in degrees celcius. + * The default is false (degrees Celcius). + * @return The last temperature reading in Celcius or Fahrenheit. + */ + float getTemperature(bool fahrenheit=false); + + /** + * Return the current state of the relay. This function will + * always return false if the relay option is not installed. + * update() must have been called prior to calling this method. + * + * @return true if the relay is active, false if inactive. + */ + bool getRelayState() + { + return m_relayState; + } + + /** + * Set the device temperature scale to Celcius of Fahrenheit. For + * devices with an LCD display, this will affect which scale is + * displayed. When changing the scale, it may take several + * seconds for the setting to take effect. + * + * @param fahrenheit true to set the scale to fahrenheit, false + * for celcius. + */ + void setTemperatureScale(bool fahrenheit); + + /** + * Get the device temperature scale. + * + * @return true if scale is fahrenheit, false for celcius. + */ + bool getTemperatureScale(); + + /** + * Get the current temperature offset. + * + * @return The configured temperature offset. + */ + float getTemperatureOffset(); + + /** + * Set the device temperature offset. The offset is applied by + * the device internally to the temperature reading. The offset + * must always be specified in degrees Celcius. Valid values must + * be between -50 and 50. + * + * @param value The temperature offset to configure. + */ + void setTemperatureOffset(float value); + + /** + * Get the current humidity offset. + * + * @return The configured humidity offset. + */ + float getHumidityOffset(); + + /** + * Set the device humidity offset. The offset is applied by the + * device internally to the humidity reading. Valid values must + * be between -100 and 100. + * + * @param value The humidity offset to configure. + */ + void setHumidityOffset(float value); + + /** + * Return the current relay set point (in PPM). This set point is + * the CO2 concentration point in PPM that causes the relay to + * trigger. + * + * @return The relay set point value. + */ + float getRelaySetPoint(); + + /** + * Set the relay set point in PPM. This set point is the CO2 + * concentration point in PPM that causes the relay to trigger. + * Valid values are between 0-65535. + * + * @param value The desired relay set point value. + */ + void setRelaySetPoint(float value); + + /** + * Return the current relay hysteresis. + * + * @return The relay hysteresis value. + */ + float getRelayHysteresis(); + + /** + * Set the relay hysteresis. Valid values are between 0-65535. + * + * @param value The desired relay set point value. + */ + void setRelayHysteresis(float value); + + /** + * Return the current elevation setting (in meters). + * + * @return The current elevation setting. + */ + float getElevation(); + + /** + * Set the elevation setting in meters. Valid values are between + * 0-65535. + * + * @param value The desired elevation setting in meters. + */ + void setElevation(float value); + + /** + * Return the current calibration single point value (in PPM). + * + * @return The current calibration single point value. + */ + float getCalibrationSinglePoint(); + + /** + * Set the calibration single point value in PPM. Valid values + * are between 0-65535. + * + * @param value The desired calibration single point value in PPM. + */ + void setCalibrationSinglePoint(float value); + + /** + * Return the current baud rate. + * + * @return The current baud rate. + */ + float getBaudRate(); + + /** + * Return the current MAC address. The MAC address is configured + * via DIP switches within the device. + * + * @return The current MAC address. + */ + float getMACAddress(); + + /** + * Return the current ABC (Automatic Background Calibration) + * logic state. See the datasheet for details. + * + * @return The current ABC logic state. + */ + bool getABCLogicState(); + + /** + * Set the ABC (Automatic Background Calibration) logic state. + * Valid values are true for ON, false for OFF. + * + * @param value The desired ABC logic state. + */ + void setABCLogicState(bool value); + + /** + * Return the current ABC (Automatic Background Calibration) + * reset state. See the datasheet for details. + * + * @return The current ABC reset state. + */ + bool getABCLogicReset(); + + /** + * Set the ABC (Automatic Background Calibration) reset state. + * Valid values are true for Reset, false for Normal. + * + * @param value The desired ABC reset state. + */ + void setABCLogicReset(bool value); + + /** + * Return the current CO2 calibration state. See the datasheet + * for details. + * + * @return The current CO2 calibration state. + */ + bool getCO2Calibration(); + + /** + * Set the CO2 calibration state. + * Valid values are true for Calibrate, false for Normal. + * + * @param value The desired ABC reset state. + */ + void setCO2Calibration(bool value); + + + protected: + float m_humidity; + // always stored in C + float m_temperature; + float m_co2; + bool m_relayState; + + private: + // Have we checked the device's temperature unit setting yet + bool m_isTempInitialized; + + // Is the device configured for Celcius? + bool m_isCelcius; + }; +}