I'm writing a program which will communicate IO values via JSON-RPC. I've got eight objects I instantiate. These objects are four different Classes, but all share a base Class BrokerData.
The first thing I would like to do is iterate over a list of these objects to access base class methods. For example, all the Objects have a getData() method which returns their current value. My searching seems to point to using a vector or list, which while not built into arduino c++ can be added(?).
The second thing I want to do is lookup objects by "name". I will be receiving JSON-RPC messages like these:
{
"method" : "status",
"params" : {
"data" : ["Voltage", "Load Power","Charge Energy"],
"style":"verbose"},
"id" : 1
}
and
{
"method" : "subscribe",
"params" : {
"data" : ["Voltage", "Charge Power", "LoadEnergy"],
"max_update_ms" : 2000},
"id" : 2
}
The parsing is handled by the aJSON library and all my objects have a getName() method which returns a matching char[] (e.g. "Voltage"). It looks like I should use a hashtable, which again is part of the std library.
While code examples would be great, I'd be happy with some general guidance on how to handle this. All my c++ experience is on arduino so I'm not really familiar with the std library. If you would like to see more of my code, I'd be happy to provide it.
Energy_monitor.ino (the first bit):
#include "ADS1115.h"
#include <aJSON.h>
#include <JsonRPCServer.h>
#include "broker_data.h"
#define ACS715_mV_per_A 133.0
#define V_DIV_LOW 10000.0
#define V_DIV_HIGH 21000.0
#define ADC_CHANNEL_LOAD_CURRENT 0
#define ADC_CHANNEL_CHARGE_CURRENT 1
#define ADC_CHANNEL_VOLTAGE 2
#define ADC_CHANNEL_VCC 3
const uint8_t ADS1115_ADDRESS = 0x48;
ADS1115 ads(ADS1115_ADDRESS);
VoltageData v_batt("Voltage", ads, ADC_CHANNEL_VOLTAGE, V_DIV_LOW, V_DIV_HIGH);
VoltageData v_cc("Vcc", ads, ADC_CHANNEL_VCC, 0, 1); // No voltage divider
CurrentData current_l("Load_Current", ads, v_cc, ADC_CHANNEL_LOAD_CURRENT, ACS715_mV_per_A);
CurrentData current_c("Charge_Current", ads, v_cc, ADC_CHANNEL_CHARGE_CURRENT, ACS715_mV_per_A);
PowerData power_l("Load Power",current_l,v_batt);
PowerData power_c("Charge Power",current_c,v_batt);
EnergyData energy_l("Load Energy", power_l);
EnergyData energy_c("Charge Energy",power_c);
TargetController jsonController(&Serial);
aJsonStream serial_stream(&Serial);
Here's broker_data.h:
#include "ADS1115.h"
#define BROKER_DATA_NAME_LENGTH 15
#define BROKER_DATA_UNIT_LENGTH 5
/*
class BrokerData is an abstract class for all data objects
*/
class BrokerData {
public:
BrokerData(char *name, char *unit) {
strncpy(_data_name, name, BROKER_DATA_NAME_LENGTH);
strncpy(_data_unit, unit, BROKER_DATA_UNIT_LENGTH);
_subscription_rate = 0;
_last_sample_time = NAN;
_subscription_time = NAN;
_data_value = NAN;
_data_max = NAN;
_data_min = NAN;
};
double getValue() { return _data_value; }
double getMax() { return _data_max; }
double getMin() { return _data_min; }
void resetMin() { _data_min = NAN; }
void resetMax() { _data_max = NAN; }
const char *getName() { return _data_name; }
const char *getUnit() { return _data_unit; }
void subscribe(uint8_t sub_rate_s) { _subscription_rate = sub_rate_s;}
void unsubscribe() { _subscription_rate = 0; _subscription_time = NAN; }
bool isSubscribed() { return (bool)_subscription_rate; }
bool subscriptionDue();
uint8_t getSubscriptionRate() { return _subscription_rate; }
void setSubscriptionTime() { _subscription_time = millis(); } // Called when subscription is generated.
uint32_t getSampleTime() { return _last_sample_time; }
virtual double getData() = 0;
protected:
uint32_t _getTimeDelta();
uint8_t _checkMinMax();
double _data_value;
double _data_max;
double _data_min;
private:
char _data_name[BROKER_DATA_NAME_LENGTH];
char _data_unit[BROKER_DATA_UNIT_LENGTH];
uint8_t _subscription_rate; // in seconds
uint32_t _subscription_time; // Time of last subscription message
uint32_t _last_sample_time; // Time of last sample
};
/*
class ADCData is an abstract intermediate class for all data objects which get their data from the ADS1115 ADC
*/
class ADCData : public BrokerData {
public:
ADCData(char *name, char *unit, ADS1115 &ads, uint8_t ADCchannel) : BrokerData(name,unit) {
_channel = ADCchannel; // should be 0-4
_ads = &ads;
}
uint16_t getADCreading();
uint8_t getChannel() { return _channel; }
protected:
ADS1115 *_ads;
private:
uint8_t _channel;
};
/*
class VoltageData is a class for all data objects which represent a voltage object
*/
class VoltageData : public ADCData {
public:
VoltageData(char *name, ADS1115 &ads, uint8_t ADCchannel, uint32_t high_div, uint32_t low_div) : ADCData(name,"V",ads,ADCchannel) {
_v_div = (high_div + low_div) / low_div;
}
double getData();
private:
double _v_div;
};
/*
class CurrentData is a class for all data objects which represent a current object
*/
class CurrentData: public ADCData {
public:
CurrentData(char *name, ADS1115 &ads,VoltageData &vcc,uint8_t ADCchannel,double mV_per_A) : ADCData(name,"A",ads,ADCchannel) {
_vcc = &vcc;
_mV_per_A = mV_per_A;
}
double getData();
private:
double _mV_per_A;
VoltageData *_vcc;
};
/*
class PowerData is a class for all data objects which represent a power object
*/
class PowerData : public BrokerData {
public:
PowerData(char *name, CurrentData ¤t, VoltageData &voltage) : BrokerData(name,"W") {
_voltage = &voltage;
_current = ¤t;
}
double getData(); // Calculates new Power based on most recent current and voltage
void resetData();
private:
CurrentData *_current;
VoltageData *_voltage;
};
/*
class EnergyData is a class for all data objects which represent an energy object
*/
class EnergyData : public BrokerData {
public:
EnergyData(char *name, PowerData &power) : BrokerData(name,"Wh") {
_power = &power;
}
double getData(); // Calculates new Energy based on most recent power
void setData(double energy_value); // Used for setting value, usually after reboot.
void resetData() { setData(0);}
private:
PowerData *_power;
};