Skip to content

Commit

Permalink
Add INA219 sensor and example (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
ba58smith authored Apr 11, 2020
1 parent 44af06a commit 240e3f9
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 0 deletions.
66 changes: 66 additions & 0 deletions examples/ina219_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// INA219_example.cpp

#include <Arduino.h>

//#define SERIAL_DEBUG_DISABLED

#define USE_LIB_WEBSOCKET true

#include "sensesp_app.h"
#include "signalk/signalk_output.h"
#include "sensors/ina219.h"

ReactESP app([] () {
#ifndef SERIAL_DEBUG_DISABLED
Serial.begin(115200);

// A small arbitrary delay is required to let the
// serial port catch up

delay(100);
Debug.setSerialEnabled(true);
#endif

// true will disable systemHz, freemem, uptime, and ipaddress "sensors"
bool disableStandardSensors = true;

sensesp_app = new SensESPApp(disableStandardSensors);

// Create an INA219, which represents the physical sensor.
// 0x40 is the default address. Chips can be modified to use 0x41 (shown here), 0x44, or 0x45.
// The default volt and amp ranges are 32V and 2A (cal32_2). Here, 32v and 1A is specified with cal32_1.
auto* pINA219 = new INA219(0x41, cal32_1);


// Define the read_delay you're going to use, if other than the default of 500 ms.
const uint read_delay = 1000; // once per second

// Create an INA219value, which is used to read a specific value from the INA219, and send its output
// to SignalK as a number (float). This one is for the bus voltage.
auto* pINA219busVoltage = new INA219value(pINA219, bus_voltage, read_delay, "someElectricDevice/busVoltage");

pINA219busVoltage->connectTo(new SKOutputNumber("electrical.someelectricdevice.busVoltage"));

// Do the same for the shunt voltage.
auto* pINA219shuntVoltage = new INA219value(pINA219, shunt_voltage, read_delay, "someElectricDevice/shuntVoltage");

pINA219shuntVoltage->connectTo(new SKOutputNumber("electrical.someelectricdevice.shuntVoltage"));

// Do the same for the current (amperage).
auto* pINA219current = new INA219value(pINA219, current, read_delay, "someElectricDevice/current");

pINA219current->connectTo(new SKOutputNumber("electrical.someelectricdevice.current"));

// Do the same for the power (watts).
auto* pINA219power = new INA219value(pINA219, power, read_delay, "someElectricDevice/power");

pINA219power->connectTo(new SKOutputNumber("electrical.someelectricdevice.power"));

// Do the same for the load voltage.
auto* pINA219loadVoltage = new INA219value(pINA219, load_voltage, read_delay, "someElectricDevice/loadVoltage");

pINA219loadVoltage->connectTo(new SKOutputNumber("electrical.someelectricdevice.loadVoltage"));


sensesp_app->enable();
});
85 changes: 85 additions & 0 deletions src/sensors/ina219.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "ina219.h"

#include "sensesp.h"
//#include "i2c_tools.h"
#include <RemoteDebug.h>


// INA219 represents an ADAfruit (or compatible) INA219 temperature / pressure / humidity sensor.
INA219::INA219(uint8_t addr, INA219CAL_t calibration_setting, String config_path) :
Sensor(config_path) {
className = "INA219";
load_configuration();
pAdafruitINA219 = new Adafruit_INA219(addr);
pAdafruitINA219->begin();
// Default calibration in the Adafruit_INA219 constructor is 32V and 2A, so that's what it will be unless
// it's set to something different in the call to this constructor:
if (calibration_setting == cal32_1) {
pAdafruitINA219->setCalibration_32V_1A();
}
else if (calibration_setting == cal16_400) {
pAdafruitINA219->setCalibration_16V_400mA();
}
}



// INA219value reads and outputs the specified type of value of a INA219 sensor
INA219value::INA219value(INA219* pINA219, INA219ValType val_type, uint read_delay, String config_path) :
NumericSensor(config_path), pINA219{pINA219}, val_type{val_type}, read_delay{read_delay} {
className = "INA219value";
load_configuration();
}

// INA219 outputs temp in Celsius. Need to convert to Kelvin before sending to Signal K.
// Pressure is output in Pascals, Humidity is output in relative humidity (0 - 100%)
void INA219value::enable() {
app.onRepeat(read_delay, [this](){
switch (val_type) {
case bus_voltage: output = pINA219->pAdafruitINA219->getBusVoltage_V();
break;
case shunt_voltage: output = (pINA219->pAdafruitINA219->getShuntVoltage_mV() / 1000); // SK wants volts, not mV
break;
case current: output = (pINA219->pAdafruitINA219->getCurrent_mA() / 1000); // SK wants amps, not mA
break;
case power: output = (pINA219->pAdafruitINA219->getPower_mW() / 1000); // SK want watts, not mW
break;
case load_voltage: output = (pINA219->pAdafruitINA219->getBusVoltage_V() + (pINA219->pAdafruitINA219->getShuntVoltage_mV() / 1000));
break;
default: debugE("FATAL: invalid val_type parameter.");
}

notify();
});
}

JsonObject& INA219value::get_configuration(JsonBuffer& buf) {
JsonObject& root = buf.createObject();
root["read_delay"] = read_delay;
root["value"] = output;
return root;
};

static const char SCHEMA[] PROGMEM = R"###({
"type": "object",
"properties": {
"read_delay": { "title": "Read delay", "type": "number", "description": "The time, in milliseconds, between each read of the input" },
"value": { "title": "Last value", "type" : "number", "readOnly": true }
}
})###";


String INA219value::get_config_schema() {
return FPSTR(SCHEMA);
}

bool INA219value::set_configuration(const JsonObject& config) {
String expected[] = {"read_delay"};
for (auto str : expected) {
if (!config.containsKey(str)) {
return false;
}
}
read_delay = config["read_delay"];
return true;
}
47 changes: 47 additions & 0 deletions src/sensors/ina219.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef _ina219_H_
#define _ina219_H_

#include <Wire.h>
#include <Adafruit_INA219.h>

#include "sensor.h"

// The INA219 classes are based on the ADAfruit_INA219 library.

// These are the used to tell the constructor what to set for maximum voltage and amperage.
// The default in the Adafruit constructor is 32V and 2A, so we only need to handle the other two.
enum INA219CAL_t { cal32_2, cal32_1, cal16_400 };

// INA219 represents an ADAfruit (or compatible) INA219 High Side DC Current Sensor.
// The constructor creates a pointer to the instance, and starts up the sensor. The pointer is
// passed to INA219value, which retrieves the specified value.
//
class INA219 : public Sensor {
public:
INA219(uint8_t addr = 0x40, INA219CAL_t calibration_setting = cal32_2, String config_path = "");
Adafruit_INA219* pAdafruitINA219;

};


// Pass one of these in the constructor to INA219value() to tell which type of value you want to output
enum INA219ValType { bus_voltage, shunt_voltage, current, power, load_voltage };

// INA219value reads and outputs the specified value of a INA219 sensor.
class INA219value : public NumericSensor {
public:
INA219value(INA219* pINA219, INA219ValType val_type, uint read_delay = 500, String config_path="");
void enable() override final;
INA219* pINA219;

private:

INA219ValType val_type;
uint read_delay;
virtual JsonObject& get_configuration(JsonBuffer& buf) override;
virtual bool set_configuration(const JsonObject& config) override;
virtual String get_config_schema() override;

};

#endif

0 comments on commit 240e3f9

Please sign in to comment.