diff --git a/documentation/CCGX-Modbus-TCP-register-list-3.73.xlsx b/documentation/CCGX-Modbus-TCP-register-list-3.73.xlsx
new file mode 100644
index 0000000..d46825d
Binary files /dev/null and b/documentation/CCGX-Modbus-TCP-register-list-3.73.xlsx differ
diff --git a/manifest.xml b/manifest.xml
index c598a5a..72b58a3 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -7,11 +7,6 @@
http://
http://
-
+
+
diff --git a/src/BatteryData.hpp b/src/BatteryData.hpp
new file mode 100644
index 0000000..ab17cb6
--- /dev/null
+++ b/src/BatteryData.hpp
@@ -0,0 +1,385 @@
+#ifndef POWER_VICTRON_BATTERY_DATA_HPP
+#define POWER_VICTRON_BATTERY_DATA_HPP
+
+#include "BatteryRegisters.hpp"
+#include
+#include
+#include
+#include
+#include
+
+namespace power_victron {
+
+ /**
+ * Struct representing com.victronenergy.battery data
+ */
+ struct BatteryData {
+ enum Alarm {
+ NONE = 0,
+ LOW_VOLTAGE_ALARM = 1 << 0,
+ HIGH_VOLTAGE_ALARM = 1 << 1,
+ LOW_STARTER_VOLTAGE_ALARM = 1 << 2,
+ HIGH_STARTER_VOLTAGE_ALARM = 1 << 3,
+ LOW_STATE_OF_CHARGE_ALARM = 1 << 4,
+ LOW_TEMPERATURE_ALARM = 1 << 5,
+ HIGH_TEMPERATURE_ALARM = 1 << 6,
+ MID_VOLTAGE_ALARM = 1 << 7,
+ LOW_FUSED_VOLTAGE_ALARM = 1 << 8,
+ HIGH_FUSED_VOLTAGE_ALARM = 1 << 9,
+ FUSE_BLOWN_ALARM = 1 << 10,
+ HIGH_INTERNAL_TEMPERATURE_ALARM = 1 << 11,
+ HIGH_CHARGE_CURRENT_ALARM = 1 << 12,
+ HIGH_DISCHARGE_CURRENT_ALARM = 1 << 13,
+ CELL_IMBALANCE_ALARM = 1 << 14,
+ INTERNAL_FAILURE_ALARM = 1 << 15,
+ HIGH_CHARGE_TEMPERATURE_ALARM = 1 << 16,
+ LOW_CHARGE_TEMPERATURE_ALARM = 1 << 17,
+ LOW_CELL_VOLTAGE_ALARM = 1 << 18,
+ BMS_CABLE_ALARM = 1 << 19,
+ BMS_CONTACTOR_RESISTANCE_ALARM = 1 << 20,
+ BMS_HIGH_CURRENT_ALARM = 1 << 21,
+ };
+
+ enum DiagnosticError {
+ NO_ERROR = 0,
+ BATTERY_INITIALIZATION_ERROR = 1,
+ NO_BATTERIES_CONNECTED = 2,
+ UNKNOWN_BATTERY_CONNECTED = 3,
+ DIFFERENT_BATTERY_TYPE = 4,
+ NUMBER_OF_BATTERIES_INCORRECT = 5,
+ LYNX_SHUNT_NOT_FOUND = 6,
+ BATTERY_MEASURE_ERROR = 7,
+ INTERNAL_CALCULATION_ERROR = 8,
+ BATTERIES_IN_SERIES_NOT_OK = 9,
+ NUMBER_OF_BATTERIES_INCORRECT_10 = 10,
+ HARDWARE_ERROR = 11,
+ WATCHDOG_ERROR = 12,
+ OVER_VOLTAGE = 13,
+ UNDER_VOLTAGE = 14,
+ OVER_TEMPERATURE = 15,
+ UNDER_TEMPERATURE = 16,
+ HARDWARE_FAULT = 17,
+ STANDBY_SHUTDOWN = 18,
+ PRE_CHARGE_CHARGE_ERROR = 19,
+ SAFETY_CONTACTOR_CHECK_ERROR = 20,
+ PRE_CHARGE_DISCHARGE_ERROR = 21,
+ ADC_ERROR = 22,
+ SLAVE_ERROR = 23,
+ SLAVE_WARNING = 24,
+ PRE_CHARGE_ERROR = 25,
+ SAFETY_CONTACTOR_ERROR = 26,
+ OVER_CURRENT = 27,
+ SLAVE_UPDATE_FAILED = 28,
+ SLAVE_UPDATE_UNAVAILABLE = 29,
+ CALIBRATION_DATA_LOST = 30,
+ SETTINGS_INVALID = 31,
+ BMS_CABLE = 32,
+ REFERENCE_FAILURE = 33,
+ WRONG_SYSTEM_VOLTAGE = 34,
+ PRE_CHARGE_TIMEOUT = 35
+ };
+
+ struct DiagnosticEvent {
+ base::Time time;
+ DiagnosticError error;
+ };
+
+ enum Mode {
+ ON = 3,
+ STANDBY = 252
+ };
+
+ enum BalancerStatus {
+ UNKNOWN = 0,
+ BALANCED = 1,
+ BALANCING = 2,
+ CELL_IMBALANCE = 3
+ };
+
+ enum State {
+ INITIALIZING_WAIT_START = 0,
+ INITIALIZING_BEFORE_BOOT = 1,
+ INITIALIZING_BEFORE_BOOT_DELAY = 2,
+ INITIALIZING_WAIT_BOOT = 3,
+ INITIALIZING = 4,
+ INITIALIZING_MEASURE_BATTERY_VOLTAGE = 5,
+ INITIALIZING_CALCULATE_BATTERY_VOLTAGE = 6,
+ INITIALIZING_WAIT_BUS_VOLTAGE = 7,
+ INITIALIZING_WAIT_FOR_LYNX_SHUNT = 8,
+ RUNNING = 9,
+ ERROR_10 = 10,
+ UNUSED_11 = 11,
+ SHUTDOWN = 12,
+ SLAVE_UPDATING = 13,
+ STATE_STANDBY = 14,
+ GOING_TO_RUN = 15,
+ PRE_CHARGING = 16,
+ CONTACTOR_CHECK = 17
+ };
+
+ struct AlarmRegister {
+ Alarm alarm;
+ BatteryRegisters register_id;
+ };
+
+ static constexpr AlarmRegister alarm_register[] = {
+ { LOW_VOLTAGE_ALARM,BatteryRegisters::LOW_VOLTAGE_ALARM },
+ { HIGH_VOLTAGE_ALARM, BatteryRegisters::HIGH_VOLTAGE_ALARM},
+ { LOW_STARTER_VOLTAGE_ALARM, BatteryRegisters::LOW_STARTER_VOLTAGE_ALARM},
+ { HIGH_STARTER_VOLTAGE_ALARM, BatteryRegisters::HIGH_STARTER_VOLTAGE_ALARM},
+ { LOW_STATE_OF_CHARGE_ALARM, BatteryRegisters::LOW_STATE_OF_CHARGE_ALARM},
+ { LOW_TEMPERATURE_ALARM, BatteryRegisters::LOW_TEMPERATURE_ALARM},
+ { HIGH_TEMPERATURE_ALARM, BatteryRegisters::HIGH_TEMPERATURE_ALARM},
+ { MID_VOLTAGE_ALARM, BatteryRegisters::MID_VOLTAGE_ALARM},
+ { LOW_FUSED_VOLTAGE_ALARM, BatteryRegisters::LOW_FUSED_VOLTAGE_ALARM},
+ { HIGH_FUSED_VOLTAGE_ALARM, BatteryRegisters::HIGH_FUSED_VOLTAGE_ALARM},
+ { FUSE_BLOWN_ALARM, BatteryRegisters::FUSE_BLOWN_ALARM},
+ {HIGH_INTERNAL_TEMPERATURE_ALARM,
+ BatteryRegisters::HIGH_INTERNAL_TEMPERATURE_ALARM },
+ { HIGH_CHARGE_CURRENT_ALARM, BatteryRegisters::HIGH_CHARGE_CURRENT_ALARM},
+ { HIGH_DISCHARGE_CURRENT_ALARM,
+ BatteryRegisters::HIGH_DISCHARGE_CURRENT_ALARM },
+ { CELL_IMBALANCE_ALARM, BatteryRegisters::CELL_IMBALANCE_ALARM},
+ { INTERNAL_FAILURE_ALARM, BatteryRegisters::INTERNAL_FAILURE_ALARM},
+ { HIGH_CHARGE_TEMPERATURE_ALARM,
+ BatteryRegisters::HIGH_CHARGE_TEMPERATURE_ALARM },
+ { LOW_CHARGE_TEMPERATURE_ALARM,
+ BatteryRegisters::LOW_CHARGE_TEMPERATURE_ALARM },
+ { LOW_CELL_VOLTAGE_ALARM, BatteryRegisters::LOW_CELL_VOLTAGE_ALARM},
+ { BMS_CABLE_ALARM, BatteryRegisters::BMS_CABLE_ALARM},
+ { BMS_CONTACTOR_RESISTANCE_ALARM,
+ BatteryRegisters::BMS_CONTACTOR_RESISTANCE_ALARM },
+ { BMS_HIGH_CURRENT_ALARM, BatteryRegisters::BMS_HIGH_CURRENT_ALARM}
+ };
+
+ /** @meta bitfield /power_victron/BatteryData/Alarm */
+ uint32_t alarms = 0;
+
+ /**
+ * @brief Battery power (W)
+ */
+ int32_t battery_power;
+ /**
+ * @brief Battery voltage (V)
+ */
+ double battery_voltage;
+ /**
+ * @brief Starter battery voltage (V)
+ */
+ double starter_battery_voltage;
+ /**
+ * @brief Current (A)
+ */
+ double current;
+ /**
+ * @brief Battery temperature
+ */
+ base::Temperature battery_temperature;
+ /**
+ * @brief Mid-point voltage of the battery bank(V)
+ */
+ double mid_point_voltage;
+ /**
+ * @brief Mid-point deviation of the battery bank (%)
+ */
+ double mid_point_deviation;
+ /**
+ * @brief Consumed Amphours (Ah)
+ */
+ double consumed_amphours;
+ /**
+ * @brief State of charge (%)
+ */
+ double state_of_charge;
+ /**
+ * @brief Relay status
+ */
+ uint32_t relay_status;
+ /**
+ * @brief Deepest discharge (Ah)
+ */
+ double deepest_discharge;
+ /**
+ * @brief Last discharge (Ah)
+ */
+ double last_discharge;
+ /**
+ * @brief Average discharge (Ah)
+ */
+ double average_discharge;
+ /**
+ * @brief Charge cycles count
+ */
+ uint32_t charge_cycles;
+ /**
+ * @brief Full discharges count
+ */
+ uint32_t full_discharges;
+ /**
+ * @brief Total Ah drawn (Ah)
+ */
+ double total_ah_drawn;
+ /**
+ * @brief Minimum voltage (V)
+ */
+ double minimum_voltage;
+ /**
+ * @brief Maximum voltage (V)
+ */
+ double maximum_voltage;
+ /**
+ * @brief Time since last full charge
+ */
+ base::Time time_since_last_full_charge;
+ /**
+ * @brief Automatic syncs count
+ */
+ uint32_t automatic_syncs;
+ /**
+ * @brief Low voltage alarms count
+ */
+ uint32_t low_voltage_alarms;
+ /**
+ * @brief High voltage alarms count
+ */
+ uint32_t high_voltage_alarms;
+ /**
+ * @brief Low starter voltage alarms count
+ */
+ uint32_t low_starter_voltage_alarms;
+ /**
+ * @brief High starter voltage alarms count
+ */
+ uint32_t high_starter_voltage_alarms;
+ /**
+ * @brief Minimum starter voltage (V)
+ */
+ double minimum_starter_voltage;
+ /**
+ * @brief Maximum starter voltage (V)
+ */
+ double maximum_starter_voltage;
+ /**
+ * @brief Low fused-voltage alarms count
+ */
+ uint32_t low_fused_voltage_alarms;
+ /**
+ * @brief High fused-voltage alarms count
+ */
+ uint32_t high_fused_voltage_alarms;
+ /**
+ * @brief Minimum fused voltage (V)
+ */
+ double minimum_fused_voltage;
+ /**
+ * @brief Maximum fused voltage (V)
+ */
+ double maximum_fused_voltage;
+ /**
+ * @brief Discharged Energy (kWh)
+ */
+ double discharged_energy;
+ /**
+ * @brief Charged Energy (kWh)
+ */
+ double charged_energy;
+ /**
+ * @brief Time to go
+ */
+ base::Time time_to_go;
+ /**
+ * @brief State of health (%)
+ */
+ double state_of_health;
+ /**
+ * @brief Max charge voltage (V)
+ */
+ double max_charge_voltage;
+ /**
+ * @brief Min discharge voltage (V)
+ */
+ double min_discharge_voltage;
+ /**
+ * @brief Max charge current (A)
+ */
+ double max_charge_current;
+ /**
+ * @brief Max discharge current (A)
+ */
+ double max_discharge_current;
+ /**
+ * @brief Capacity (Ah)
+ */
+ double capacity;
+ /**
+ * @brief History of last diagnostic errors
+ *
+ * index 0 is the most recent (1st last error), while index 3 is the oldest (4th
+ * last error).
+ */
+ std::vector diagnostics_errors;
+ /**
+ * @brief Minimum cell temperature
+ */
+ base::Temperature minimum_cell_temperature;
+ /**
+ * @brief Maximum cell temperature
+ */
+ base::Temperature maximum_cell_temperature;
+ /**
+ * @brief Consumed Amphours (Ah)
+ */
+ double consumed_amphours_1;
+ /**
+ * @brief State
+ */
+ State state;
+ /**
+ * @brief Error
+ */
+ DiagnosticError error_code;
+ /**
+ * @brief System-switch
+ */
+ bool system_switch;
+ /**
+ * @brief Balancing
+ */
+ bool balancing;
+ /**
+ * @brief System minimum cell voltage (V)
+ */
+ double system_minimum_cell_voltage;
+ /**
+ * @brief System maximum cell voltage (V)
+ */
+ double system_maximum_cell_voltage;
+ /**
+ * @brief Diagnostics shutdowns due to error count
+ *
+ */
+ uint32_t diagnostics_shutdowns_due_to_error;
+ /**
+ * @brief Historical min cell-voltage (V)
+ */
+ double historical_min_cell_voltage;
+ /**
+ * @brief Historical max cell-voltage (V)
+ */
+ double historical_max_cell_voltage;
+ /**
+ * @brief Mode
+ */
+ Mode mode;
+ /**
+ * @brief Balancer status
+ */
+ BalancerStatus balancer_status;
+ /**
+ * @brief Connection information
+ */
+ std::string connection_information;
+ };
+}
+
+#endif
diff --git a/src/BatteryRegisters.hpp b/src/BatteryRegisters.hpp
new file mode 100644
index 0000000..4f01525
--- /dev/null
+++ b/src/BatteryRegisters.hpp
@@ -0,0 +1,116 @@
+#ifndef POWER_VICTRON_BATTERY_REGISTERS_HPP
+#define POWER_VICTRON_BATTERY_REGISTERS_HPP
+
+namespace power_victron {
+
+ enum BatteryRegisters {
+ BATTERY_POWER = 256,
+ BATTERY_POWER_2 = 258,
+ BATTERY_VOLTAGE = 259,
+ STARTER_BATTERY_VOLTAGE = 260,
+ CURRENT = 261,
+ BATTERY_TEMPERATURE = 262,
+ MID_POINT_VOLTAGE_OF_THE_BATTERY_BANK = 263,
+ MID_POINT_DEVIATION_OF_THE_BATTERY_BANK = 264,
+ CONSUMED_AMPHOURS = 265,
+ STATE_OF_CHARGE = 266,
+ ALARM = 267,
+ LOW_VOLTAGE_ALARM = 268,
+ HIGH_VOLTAGE_ALARM = 269,
+ LOW_STARTER_VOLTAGE_ALARM = 270,
+ HIGH_STARTER_VOLTAGE_ALARM = 271,
+ LOW_STATE_OF_CHARGE_ALARM = 272,
+ LOW_TEMPERATURE_ALARM = 273,
+ HIGH_TEMPERATURE_ALARM = 274,
+ MID_VOLTAGE_ALARM = 275,
+ LOW_FUSED_VOLTAGE_ALARM = 276,
+ HIGH_FUSED_VOLTAGE_ALARM = 277,
+ FUSE_BLOWN_ALARM = 278,
+ HIGH_INTERNAL_TEMPERATURE_ALARM = 279,
+ RELAY_STATUS = 280,
+ DEEPEST_DISCHARGE = 281,
+ LAST_DISCHARGE = 282,
+ AVERAGE_DISCHARGE = 283,
+ CHARGE_CYCLES = 284,
+ FULL_DISCHARGES = 285,
+ TOTAL_AH_DRAWN = 286,
+ MINIMUM_VOLTAGE = 287,
+ MAXIMUM_VOLTAGE = 288,
+ TIME_SINCE_LAST_FULL_CHARGE = 289,
+ AUTOMATIC_SYNCS = 290,
+ LOW_VOLTAGE_ALARMS = 291,
+ HIGH_VOLTAGE_ALARMS = 292,
+ LOW_STARTER_VOLTAGE_ALARMS = 293,
+ HIGH_STARTER_VOLTAGE_ALARMS = 294,
+ MINIMUM_STARTER_VOLTAGE = 295,
+ MAXIMUM_STARTER_VOLTAGE = 296,
+ LOW_FUSED_VOLTAGE_ALARMS = 297,
+ HIGH_FUSED_VOLTAGE_ALARMS = 298,
+ MINIMUM_FUSED_VOLTAGE = 299,
+ MAXIMUM_FUSED_VOLTAGE = 300,
+ DISCHARGED_ENERGY = 301,
+ CHARGED_ENERGY = 302,
+ TIME_TO_GO = 303,
+ STATE_OF_HEALTH = 304,
+ MAX_CHARGE_VOLTAGE = 305,
+ MIN_DISCHARGE_VOLTAGE = 306,
+ MAX_CHARGE_CURRENT = 307,
+ MAX_DISCHARGE_CURRENT = 308,
+ CAPACITY = 309,
+ DIAGNOSTICS_1ST_LAST_ERROR_TIMESTAMP = 310,
+ DIAGNOSTICS_2ND_LAST_ERROR_TIMESTAMP = 312,
+ DIAGNOSTICS_3RD_LAST_ERROR_TIMESTAMP = 314,
+ DIAGNOSTICS_4TH_LAST_ERROR_TIMESTAMP = 316,
+ MINIMUM_CELL_TEMPERATURE = 318,
+ MAXIMUM_CELL_TEMPERATURE = 319,
+ HIGH_CHARGE_CURRENT_ALARM = 320,
+ HIGH_DISCHARGE_CURRENT_ALARM = 321,
+ CELL_IMBALANCE_ALARM = 322,
+ INTERNAL_FAILURE_ALARM = 323,
+ HIGH_CHARGE_TEMPERATURE_ALARM = 324,
+ LOW_CHARGE_TEMPERATURE_ALARM = 325,
+ LOW_CELL_VOLTAGE_ALARM = 326,
+ BMS_CABLE_ALARM = 327,
+ BMS_CONTACTOR_RESISTANCE_ALARM = 328,
+ BMS_HIGH_CURRENT_ALARM = 329,
+ CONSUMED_AMPHOURS_2 = 330,
+ STATE = 1282,
+ ERROR = 1283,
+ SYSTEM_SWITCH = 1284,
+ BALANCING = 1285,
+ SYSTEM_NUMBER_OF_BATTERIES = 1286,
+ SYSTEM_BATTERIES_PARALLEL = 1287,
+ SYSTEM_BATTERIES_SERIES = 1288,
+ SYSTEM_NUMBER_OF_CELLS_PER_BATTERY = 1289,
+ SYSTEM_MINIMUM_CELL_VOLTAGE = 1290,
+ SYSTEM_MAXIMUM_CELL_VOLTAGE = 1291,
+ DIAGNOSTICS_SHUTDOWNS_DUE_TO_ERROR = 1292,
+ DIAGNOSTICS_1ST_LAST_ERROR = 1293,
+ DIAGNOSTICS_2ND_LAST_ERROR = 1294,
+ DIAGNOSTICS_3RD_LAST_ERROR = 1295,
+ DIAGNOSTICS_4TH_LAST_ERROR = 1296,
+ IO_ALLOW_TO_CHARGE = 1297,
+ IO_ALLOW_TO_DISCHARGE = 1298,
+ IO_EXTERNAL_RELAY = 1299,
+ HISTORY_MIN_CELL_VOLTAGE = 1300,
+ HISTORY_MAX_CELL_VOLTAGE = 1301,
+ SYSTEM_NUMBER_OF_MODULES_OFFLINE = 1302,
+ SYSTEM_NUMBER_OF_MODULES_ONLINE = 1303,
+ SYSTEM_NUMBER_OF_MODULES_BLOCKING_CHARGE = 1304,
+ SYSTEM_NUMBER_OF_MODULES_BLOCKING_DISCHARGE = 1305,
+ SYSTEM_ID_OF_MODULE_WITH_LOWEST_CELL_VOLTAGE = 1306,
+ SYSTEM_ID_OF_MODULE_WITH_HIGHEST_CELL_VOLTAGE = 1310,
+ SYSTEM_ID_OF_MODULE_WITH_LOWEST_CELL_TEMPERATURE = 1314,
+ SYSTEM_ID_OF_MODULE_WITH_HIGHEST_CELL_TEMPERATURE = 1318,
+ MODE = 1322,
+ BALANCER_STATUS = 1323,
+ SMARTLITHIUM_ERROR_FLAG_COMMUNICATION = 1324,
+ SMARTLITHIUM_ERROR_FLAG_VOLTAGE = 1325,
+ SMARTLITHIUM_ERROR_FLAG_BATTERY_NUMBER = 1326,
+ SMARTLITHIUM_ERROR_FLAG_INVALID_CONFIGURATION = 1327,
+ CONNECTION_INFORMATION = 1328,
+ };
+
+}
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 577e4a3..ef751fa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,7 @@
rock_library(power_victron
- SOURCES Dummy.cpp
- HEADERS Dummy.hpp)
+ SOURCES Driver.cpp
+ HEADERS Driver.hpp BatteryRegisters.hpp BatteryData.hpp
+ DEPS_PKGCONFIG modbus)
-rock_executable(power_victron_bin Main.cpp
+rock_executable(power_victron_read_battery ReadBatteryData.cpp
DEPS power_victron)
-
diff --git a/src/Driver.cpp b/src/Driver.cpp
new file mode 100644
index 0000000..8dbc1a6
--- /dev/null
+++ b/src/Driver.cpp
@@ -0,0 +1,187 @@
+#include
+
+using namespace power_victron;
+
+constexpr BatteryData::AlarmRegister BatteryData::alarm_register[];
+
+Driver::Driver()
+ : modbus::TCPMaster(252)
+{
+}
+
+void Driver::setAddress(int address)
+{
+ m_address = address;
+}
+
+BatteryData Driver::readBatteryData()
+{
+ BatteryData data;
+ uint32_t alarms_val = 0;
+ for (const auto& ar : BatteryData::alarm_register) {
+ if (readSingleRegister(m_address, true, ar.register_id) == 2) {
+ alarms_val |= ar.alarm;
+ }
+ }
+ data.alarms = alarms_val;
+
+ {
+ auto regs = readRegisters(m_address, true, BatteryRegisters::BATTERY_POWER, 2);
+ data.battery_power = (static_cast(regs[0]) << 16) | regs[1];
+ }
+ data.battery_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::BATTERY_VOLTAGE) / 100.0;
+ data.starter_battery_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::STARTER_BATTERY_VOLTAGE) /
+ 100.0;
+ data.current = readSingleRegister(m_address, true, BatteryRegisters::CURRENT) / 10.0;
+ data.battery_temperature = base::Temperature::fromCelsius(
+ readSingleRegister(m_address, true, BatteryRegisters::BATTERY_TEMPERATURE) /
+ 10.0);
+ data.mid_point_voltage =
+ readSingleRegister(m_address,
+ true,
+ BatteryRegisters::MID_POINT_VOLTAGE_OF_THE_BATTERY_BANK) /
+ 100.0;
+ data.mid_point_deviation =
+ readSingleRegister(m_address,
+ true,
+ BatteryRegisters::MID_POINT_DEVIATION_OF_THE_BATTERY_BANK) /
+ 100.0;
+ data.consumed_amphours =
+ readSingleRegister(m_address, true, BatteryRegisters::CONSUMED_AMPHOURS) * 10.0;
+ data.state_of_charge =
+ readSingleRegister(m_address, true, BatteryRegisters::STATE_OF_CHARGE) / 10.0;
+ data.relay_status =
+ readSingleRegister(m_address, false, BatteryRegisters::RELAY_STATUS);
+ data.deepest_discharge =
+ readSingleRegister(m_address, true, BatteryRegisters::DEEPEST_DISCHARGE) * 10.0;
+ data.last_discharge =
+ readSingleRegister(m_address, true, BatteryRegisters::LAST_DISCHARGE) * 10.0;
+ data.average_discharge =
+ readSingleRegister(m_address, true, BatteryRegisters::AVERAGE_DISCHARGE) * 10.0;
+ data.charge_cycles =
+ readSingleRegister(m_address, true, BatteryRegisters::CHARGE_CYCLES);
+ data.full_discharges =
+ readSingleRegister(m_address, true, BatteryRegisters::FULL_DISCHARGES);
+ data.total_ah_drawn =
+ readSingleRegister(m_address, true, BatteryRegisters::TOTAL_AH_DRAWN) * 10.0;
+ data.minimum_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MINIMUM_VOLTAGE) / 100.0;
+ data.maximum_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MAXIMUM_VOLTAGE) / 100.0;
+ data.time_since_last_full_charge =
+ base::Time::fromSeconds(readSingleRegister(m_address,
+ true,
+ BatteryRegisters::TIME_SINCE_LAST_FULL_CHARGE) /
+ 0.01);
+ data.automatic_syncs =
+ readSingleRegister(m_address, true, BatteryRegisters::AUTOMATIC_SYNCS);
+ data.low_voltage_alarms =
+ readSingleRegister(m_address, true, BatteryRegisters::LOW_VOLTAGE_ALARMS);
+ data.high_voltage_alarms =
+ readSingleRegister(m_address, true, BatteryRegisters::HIGH_VOLTAGE_ALARMS);
+ data.low_starter_voltage_alarms =
+ readSingleRegister(m_address, true, BatteryRegisters::LOW_STARTER_VOLTAGE_ALARMS);
+ data.high_starter_voltage_alarms = readSingleRegister(m_address,
+ true,
+ BatteryRegisters::HIGH_STARTER_VOLTAGE_ALARMS);
+ data.minimum_starter_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MINIMUM_STARTER_VOLTAGE) /
+ 100.0;
+ data.maximum_starter_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MAXIMUM_STARTER_VOLTAGE) /
+ 100.0;
+ data.low_fused_voltage_alarms =
+ readSingleRegister(m_address, true, BatteryRegisters::LOW_FUSED_VOLTAGE_ALARMS);
+ data.high_fused_voltage_alarms =
+ readSingleRegister(m_address, true, BatteryRegisters::HIGH_FUSED_VOLTAGE_ALARMS);
+ data.minimum_fused_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MINIMUM_FUSED_VOLTAGE) /
+ 100.0;
+ data.maximum_fused_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MAXIMUM_FUSED_VOLTAGE) /
+ 100.0;
+ data.discharged_energy =
+ readSingleRegister(m_address, true, BatteryRegisters::DISCHARGED_ENERGY) / 10.0;
+ data.charged_energy =
+ readSingleRegister(m_address, true, BatteryRegisters::CHARGED_ENERGY) / 10.0;
+ data.time_to_go = base::Time::fromSeconds(
+ readSingleRegister(m_address, true, BatteryRegisters::TIME_TO_GO) / 0.01);
+ data.state_of_health =
+ readSingleRegister(m_address, true, BatteryRegisters::STATE_OF_HEALTH) / 10.0;
+ data.max_charge_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MAX_CHARGE_VOLTAGE) / 10.0;
+ data.min_discharge_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::MIN_DISCHARGE_VOLTAGE) /
+ 10.0;
+ data.max_charge_current =
+ readSingleRegister(m_address, true, BatteryRegisters::MAX_CHARGE_CURRENT) / 10.0;
+ data.max_discharge_current =
+ readSingleRegister(m_address, true, BatteryRegisters::MAX_DISCHARGE_CURRENT) /
+ 10.0;
+ data.capacity =
+ readSingleRegister(m_address, true, BatteryRegisters::CAPACITY) / 10.0;
+ data.diagnostics_errors.resize(4);
+ uint16_t time_regs[] = {BatteryRegisters::DIAGNOSTICS_1ST_LAST_ERROR_TIMESTAMP,
+ BatteryRegisters::DIAGNOSTICS_2ND_LAST_ERROR_TIMESTAMP,
+ BatteryRegisters::DIAGNOSTICS_3RD_LAST_ERROR_TIMESTAMP,
+ BatteryRegisters::DIAGNOSTICS_4TH_LAST_ERROR_TIMESTAMP};
+ uint16_t error_regs[] = {BatteryRegisters::DIAGNOSTICS_1ST_LAST_ERROR,
+ BatteryRegisters::DIAGNOSTICS_2ND_LAST_ERROR,
+ BatteryRegisters::DIAGNOSTICS_3RD_LAST_ERROR,
+ BatteryRegisters::DIAGNOSTICS_4TH_LAST_ERROR};
+ for (int i = 0; i < 4; ++i) {
+ auto regs = readRegisters(m_address, true, time_regs[i], 2);
+ uint32_t val = (static_cast(regs[0]) << 16) | regs[1];
+ data.diagnostics_errors[i].time =
+ base::Time::fromSeconds(static_cast(val));
+ data.diagnostics_errors[i].error = static_cast(
+ readSingleRegister(m_address, true, error_regs[i]));
+ }
+ data.minimum_cell_temperature = base::Temperature::fromCelsius(
+ readSingleRegister(m_address, true, BatteryRegisters::MINIMUM_CELL_TEMPERATURE) /
+ 10.0);
+ data.maximum_cell_temperature = base::Temperature::fromCelsius(
+ readSingleRegister(m_address, true, BatteryRegisters::MAXIMUM_CELL_TEMPERATURE) /
+ 10.0);
+ {
+ auto regs =
+ readRegisters(m_address, true, BatteryRegisters::CONSUMED_AMPHOURS_2, 2);
+ data.consumed_amphours_1 = (static_cast(regs[0]) << 16) | regs[1];
+ }
+ data.state = static_cast(
+ readSingleRegister(m_address, true, BatteryRegisters::STATE));
+ data.error_code = static_cast(
+ readSingleRegister(m_address, true, BatteryRegisters::ERROR));
+ data.system_switch =
+ (readSingleRegister(m_address, true, BatteryRegisters::SYSTEM_SWITCH) == 1);
+ data.balancing =
+ (readSingleRegister(m_address, true, BatteryRegisters::BALANCING) == 1);
+ data.system_minimum_cell_voltage =
+ readSingleRegister(m_address,
+ true,
+ BatteryRegisters::SYSTEM_MINIMUM_CELL_VOLTAGE) /
+ 100.0;
+ data.system_maximum_cell_voltage =
+ readSingleRegister(m_address,
+ true,
+ BatteryRegisters::SYSTEM_MAXIMUM_CELL_VOLTAGE) /
+ 100.0;
+ data.diagnostics_shutdowns_due_to_error = readSingleRegister(m_address,
+ true,
+ BatteryRegisters::DIAGNOSTICS_SHUTDOWNS_DUE_TO_ERROR);
+ data.historical_min_cell_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::HISTORY_MIN_CELL_VOLTAGE) /
+ 100.0;
+ data.historical_max_cell_voltage =
+ readSingleRegister(m_address, true, BatteryRegisters::HISTORY_MAX_CELL_VOLTAGE) /
+ 100.0;
+ data.mode = static_cast(
+ readSingleRegister(m_address, false, BatteryRegisters::MODE));
+ data.balancer_status = static_cast(
+ readSingleRegister(m_address, true, BatteryRegisters::BALANCER_STATUS));
+ // TODO:
+ // data.connection_information = "";
+ return data;
+}
diff --git a/src/Driver.hpp b/src/Driver.hpp
new file mode 100644
index 0000000..c36e2f7
--- /dev/null
+++ b/src/Driver.hpp
@@ -0,0 +1,30 @@
+#ifndef POWER_VICTRON_DRIVER_HPP
+#define POWER_VICTRON_DRIVER_HPP
+
+#include
+#include
+#include
+#include "BatteryData.hpp"
+#include "BatteryRegisters.hpp"
+
+namespace power_victron {
+
+ /**
+ * Driver for Victron devices using Modbus TCP
+ */
+ class Driver : public modbus::TCPMaster {
+ int m_address;
+
+ public:
+ Driver();
+
+ /**
+ * Set the Modbus address (Unit ID) for the device
+ */
+ void setAddress(int address);
+
+ BatteryData readBatteryData();
+ };
+}
+
+#endif
diff --git a/src/Dummy.cpp b/src/Dummy.cpp
deleted file mode 100644
index 46b7c17..0000000
--- a/src/Dummy.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "Dummy.hpp"
-#include
-
-using namespace std;
-using namespace power_victron;
-
-void DummyClass::welcome()
-{
- cout << "You successfully compiled and executed DummyProject. Welcome!" << endl;
-}
diff --git a/src/Dummy.hpp b/src/Dummy.hpp
deleted file mode 100644
index 82542ba..0000000
--- a/src/Dummy.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _DUMMYPROJECT_DUMMY_HPP_
-#define _DUMMYPROJECT_DUMMY_HPP_
-
-namespace power_victron {
- class DummyClass {
- public:
- /**
- * Print a welcome to stdout
- * \return nothing
- */
- void welcome();
- };
-
-} // end namespace power_victron
-
-#endif // _DUMMYPROJECT_DUMMY_HPP_
diff --git a/src/Main.cpp b/src/Main.cpp
deleted file mode 100644
index 05b78f7..0000000
--- a/src/Main.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include
-#include
-
-int main(int argc, char** argv)
-{
- power_victron::DummyClass dummyClass;
- dummyClass.welcome();
-
- return 0;
-}
diff --git a/src/ReadBatteryData.cpp b/src/ReadBatteryData.cpp
new file mode 100644
index 0000000..b6aa67a
--- /dev/null
+++ b/src/ReadBatteryData.cpp
@@ -0,0 +1,123 @@
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+using namespace power_victron;
+
+void usage()
+{
+ cout << "Usage: power_victron_read_battery " << endl;
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 4) {
+ usage();
+ return 1;
+ }
+
+ string ip = argv[1];
+ string port = argv[2];
+ int address = stoi(argv[3]);
+
+ Driver driver;
+ driver.setAddress(address);
+ try {
+ driver.openURI("tcp://" + ip + ":" + port);
+ }
+ catch (const std::exception& e) {
+ cerr << "Error opening connection: " << e.what() << endl;
+ return 1;
+ }
+
+ while (true) {
+ try {
+ BatteryData data = driver.readBatteryData();
+ cout << "\033[2J\033[H";
+ cout << "--- Battery Data (Address 226) ---" << endl;
+ cout << "alarms: " << data.alarms << endl;
+ cout << "battery_power: " << data.battery_power << endl;
+ cout << "battery_voltage: " << data.battery_voltage << endl;
+ cout << "starter_battery_voltage: " << data.starter_battery_voltage << endl;
+ cout << "current: " << data.current << endl;
+ cout << "battery_temperature: " << data.battery_temperature.getCelsius()
+ << endl;
+ cout << "mid_point_voltage: " << data.mid_point_voltage << endl;
+ cout << "mid_point_deviation: " << data.mid_point_deviation << endl;
+ cout << "consumed_amphours: " << data.consumed_amphours << endl;
+ cout << "state_of_charge: " << data.state_of_charge << endl;
+ cout << "relay_status: " << data.relay_status << endl;
+ cout << "deepest_discharge: " << data.deepest_discharge << endl;
+ cout << "last_discharge: " << data.last_discharge << endl;
+ cout << "average_discharge: " << data.average_discharge << endl;
+ cout << "charge_cycles: " << data.charge_cycles << endl;
+ cout << "full_discharges: " << data.full_discharges << endl;
+ cout << "total_ah_drawn: " << data.total_ah_drawn << endl;
+ cout << "minimum_voltage: " << data.minimum_voltage << endl;
+ cout << "maximum_voltage: " << data.maximum_voltage << endl;
+ cout << "time_since_last_full_charge: "
+ << data.time_since_last_full_charge.toSeconds() << endl;
+ cout << "automatic_syncs: " << data.automatic_syncs << endl;
+ cout << "low_voltage_alarms: " << data.low_voltage_alarms << endl;
+ cout << "high_voltage_alarms: " << data.high_voltage_alarms << endl;
+ cout << "low_starter_voltage_alarms: " << data.low_starter_voltage_alarms
+ << endl;
+ cout << "high_starter_voltage_alarms: " << data.high_starter_voltage_alarms
+ << endl;
+ cout << "minimum_starter_voltage: " << data.minimum_starter_voltage << endl;
+ cout << "maximum_starter_voltage: " << data.maximum_starter_voltage << endl;
+ cout << "low_fused_voltage_alarms: " << data.low_fused_voltage_alarms << endl;
+ cout << "high_fused_voltage_alarms: " << data.high_fused_voltage_alarms
+ << endl;
+ cout << "minimum_fused_voltage: " << data.minimum_fused_voltage << endl;
+ cout << "maximum_fused_voltage: " << data.maximum_fused_voltage << endl;
+ cout << "discharged_energy: " << data.discharged_energy << endl;
+ cout << "charged_energy: " << data.charged_energy << endl;
+ cout << "time_to_go: " << data.time_to_go.toSeconds() << endl;
+ cout << "state_of_health: " << data.state_of_health << endl;
+ cout << "max_charge_voltage: " << data.max_charge_voltage << endl;
+ cout << "min_discharge_voltage: " << data.min_discharge_voltage << endl;
+ cout << "max_charge_current: " << data.max_charge_current << endl;
+ cout << "max_discharge_current: " << data.max_discharge_current << endl;
+ cout << "capacity: " << data.capacity << endl;
+ cout << "diagnostics_errors: " << endl;
+ for (size_t i = 0; i < data.diagnostics_errors.size(); ++i) {
+ cout << " [" << i
+ << "] Time: " << data.diagnostics_errors[i].time.toSeconds()
+ << " Error: " << static_cast(data.diagnostics_errors[i].error)
+ << endl;
+ }
+ cout << "minimum_cell_temperature: "
+ << data.minimum_cell_temperature.getCelsius() << endl;
+ cout << "maximum_cell_temperature: "
+ << data.maximum_cell_temperature.getCelsius() << endl;
+ cout << "consumed_amphours_1: " << data.consumed_amphours_1 << endl;
+ cout << "state: " << data.state << endl;
+ cout << "error_code: " << static_cast(data.error_code) << endl;
+ cout << std::boolalpha;
+ cout << "system_switch: " << data.system_switch << endl;
+ cout << "balancing: " << data.balancing << endl;
+ cout << std::noboolalpha;
+ cout << "system_minimum_cell_voltage: " << data.system_minimum_cell_voltage
+ << endl;
+ cout << "system_maximum_cell_voltage: " << data.system_maximum_cell_voltage
+ << endl;
+ cout << "diagnostics_shutdowns_due_to_error: "
+ << data.diagnostics_shutdowns_due_to_error << endl;
+ cout << "historical_min_cell_voltage: " << data.historical_min_cell_voltage << endl;
+ cout << "historical_max_cell_voltage: " << data.historical_max_cell_voltage << endl;
+ cout << "mode: " << static_cast(data.mode) << endl;
+ cout << "balancer_status: " << static_cast(data.balancer_status) << endl;
+ cout << "connection_information: " << data.connection_information << endl;
+ }
+ catch (const std::exception& e) {
+ cerr << "Error during Modbus operation: " << e.what() << endl;
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ }
+
+ return 0;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ffc9fa5..b42d3df 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,3 +1,3 @@
-rock_testsuite(test_suite suite.cpp
- test_Dummy.cpp
+rock_gtest(test_suite suite.cpp
+ test_Driver.cpp
DEPS power_victron)
diff --git a/test/Helpers.hpp b/test/Helpers.hpp
new file mode 100644
index 0000000..d9d261e
--- /dev/null
+++ b/test/Helpers.hpp
@@ -0,0 +1,103 @@
+#ifndef POWER_VICTRON_HELPERS_HPP
+#define POWER_VICTRON_HELPERS_HPP
+
+#include
+#include
+
+namespace power_victron {
+
+template
+struct Helpers {
+ Test& test;
+ int transactionID = 0;
+
+ Helpers(Test& test);
+
+ void EXPECT_MODBUS_WRITE(int address, int registerID, uint16_t value);
+ void EXPECT_MODBUS_WRITE_COIL(int address, int registerID, bool value);
+ void EXPECT_MODBUS_READ(
+ int address, bool input,
+ int register_id, std::vector expected_values
+ );
+
+ int allocateTransactionID();
+};
+
+template
+Helpers::Helpers(Test& test)
+ : test(test) {
+}
+
+template
+int Helpers::allocateTransactionID() {
+ return 0xAA00 | ++transactionID;
+}
+
+template
+void Helpers::EXPECT_MODBUS_WRITE(
+ int address, int registerID, uint16_t value
+) {
+ int transactionID = allocateTransactionID();
+
+ uint8_t requestFrame[256];
+ uint8_t* requestEnd = modbus::TCP::formatWriteRegister(
+ requestFrame, transactionID, address, registerID, value
+ );
+
+ uint8_t responseFrame[256];
+ uint8_t* responseEnd = modbus::TCP::formatFrame(
+ responseFrame, transactionID, address, modbus::FUNCTION_WRITE_SINGLE_REGISTER,
+ nullptr, nullptr
+ );
+
+ test.EXPECT_REPLY(std::vector(requestFrame, requestEnd),
+ std::vector(responseFrame, responseEnd));
+}
+
+template
+void Helpers::EXPECT_MODBUS_WRITE_COIL(
+ int address, int registerID, bool value
+) {
+ int transactionID = allocateTransactionID();
+
+ uint8_t requestFrame[256];
+ uint8_t* requestEnd = modbus::TCP::formatWriteSingleCoil(
+ requestFrame, transactionID, address, registerID, value
+ );
+
+ test.EXPECT_REPLY(std::vector(requestFrame, requestEnd),
+ std::vector(requestFrame, requestEnd));
+}
+
+template
+void Helpers::EXPECT_MODBUS_READ(
+ int address, bool input, int start, std::vector expected_values
+) {
+ int transactionID = allocateTransactionID();
+
+ uint8_t requestFrame[256];
+ uint8_t* requestEnd = modbus::TCP::formatReadRegisters(
+ requestFrame, transactionID, address, input, start, expected_values.size()
+ );
+
+ uint8_t responseFrame[256];
+ uint8_t size_in_bytes = expected_values.size() * 2;
+ std::vector responsePayload{ size_in_bytes };
+ for (auto v : expected_values) {
+ responsePayload.push_back((v >> 8) & 0xFF);
+ responsePayload.push_back(v & 0xFF);
+ }
+ int function = input ? modbus::FUNCTION_READ_INPUT_REGISTERS :
+ modbus::FUNCTION_READ_HOLDING_REGISTERS;
+ uint8_t* responseEnd = modbus::TCP::formatFrame(
+ responseFrame, transactionID, address, function,
+ &responsePayload[0], &responsePayload[0] + responsePayload.size()
+ );
+
+ test.EXPECT_REPLY(std::vector(requestFrame, requestEnd),
+ std::vector(responseFrame, responseEnd));
+}
+
+}
+
+#endif
diff --git a/test/suite.cpp b/test/suite.cpp
index af38cdc..4d820af 100644
--- a/test/suite.cpp
+++ b/test/suite.cpp
@@ -1,5 +1,6 @@
-// Do NOT add anything to this file
-// This header from boost takes ages to compile, so we make sure it is compiled
-// only once (here)
-#define BOOST_TEST_MAIN
-#include
+#include
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/test_Driver.cpp b/test/test_Driver.cpp
new file mode 100644
index 0000000..a8901ca
--- /dev/null
+++ b/test/test_Driver.cpp
@@ -0,0 +1,197 @@
+#include "Helpers.hpp"
+#include
+#include
+#include
+
+using namespace power_victron;
+
+struct DriverTest : public testing::Test,
+ public iodrivers_base::Fixture,
+ public Helpers {
+ DriverTest()
+ : Helpers(*this)
+ {
+ }
+};
+
+TEST_F(DriverTest, it_reads_battery_data)
+{
+ IODRIVERS_BASE_MOCK();
+ driver.setAddress(12);
+
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_VOLTAGE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_VOLTAGE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_STARTER_VOLTAGE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_STARTER_VOLTAGE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_STATE_OF_CHARGE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_TEMPERATURE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_TEMPERATURE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MID_VOLTAGE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_FUSED_VOLTAGE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_FUSED_VOLTAGE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::FUSE_BLOWN_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_INTERNAL_TEMPERATURE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_CHARGE_CURRENT_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_DISCHARGE_CURRENT_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CELL_IMBALANCE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::INTERNAL_FAILURE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_CHARGE_TEMPERATURE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_CHARGE_TEMPERATURE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_CELL_VOLTAGE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BMS_CABLE_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BMS_CONTACTOR_RESISTANCE_ALARM, {0});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BMS_HIGH_CURRENT_ALARM, {2});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BATTERY_POWER, {0, 23});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BATTERY_VOLTAGE, {24});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::STARTER_BATTERY_VOLTAGE, {25});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CURRENT, {26});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BATTERY_TEMPERATURE, {27});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::MID_POINT_VOLTAGE_OF_THE_BATTERY_BANK,
+ {28});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::MID_POINT_DEVIATION_OF_THE_BATTERY_BANK,
+ {29});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CONSUMED_AMPHOURS, {30});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::STATE_OF_CHARGE, {31});
+ EXPECT_MODBUS_READ(12, false, BatteryRegisters::RELAY_STATUS, {32});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DEEPEST_DISCHARGE, {33});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LAST_DISCHARGE, {34});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::AVERAGE_DISCHARGE, {35});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CHARGE_CYCLES, {36});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::FULL_DISCHARGES, {37});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::TOTAL_AH_DRAWN, {38});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MINIMUM_VOLTAGE, {39});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAXIMUM_VOLTAGE, {40});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::TIME_SINCE_LAST_FULL_CHARGE, {41});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::AUTOMATIC_SYNCS, {42});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_VOLTAGE_ALARMS, {43});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_VOLTAGE_ALARMS, {44});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_STARTER_VOLTAGE_ALARMS, {45});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_STARTER_VOLTAGE_ALARMS, {46});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MINIMUM_STARTER_VOLTAGE, {47});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAXIMUM_STARTER_VOLTAGE, {48});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::LOW_FUSED_VOLTAGE_ALARMS, {49});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HIGH_FUSED_VOLTAGE_ALARMS, {50});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MINIMUM_FUSED_VOLTAGE, {51});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAXIMUM_FUSED_VOLTAGE, {52});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DISCHARGED_ENERGY, {53});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CHARGED_ENERGY, {54});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::TIME_TO_GO, {55});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::STATE_OF_HEALTH, {56});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAX_CHARGE_VOLTAGE, {57});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MIN_DISCHARGE_VOLTAGE, {58});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAX_CHARGE_CURRENT, {59});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAX_DISCHARGE_CURRENT, {60});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CAPACITY, {61});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::DIAGNOSTICS_1ST_LAST_ERROR_TIMESTAMP,
+ {0, 62});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DIAGNOSTICS_1ST_LAST_ERROR, {63});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::DIAGNOSTICS_2ND_LAST_ERROR_TIMESTAMP,
+ {0, 64});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DIAGNOSTICS_2ND_LAST_ERROR, {65});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::DIAGNOSTICS_3RD_LAST_ERROR_TIMESTAMP,
+ {0, 66});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DIAGNOSTICS_3RD_LAST_ERROR, {67});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::DIAGNOSTICS_4TH_LAST_ERROR_TIMESTAMP,
+ {0, 68});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::DIAGNOSTICS_4TH_LAST_ERROR, {69});
+
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MINIMUM_CELL_TEMPERATURE, {70});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::MAXIMUM_CELL_TEMPERATURE, {71});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::CONSUMED_AMPHOURS_2, {0, 72});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::STATE, {73});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::ERROR, {74});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::SYSTEM_SWITCH, {75});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BALANCING, {76});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::SYSTEM_MINIMUM_CELL_VOLTAGE, {77});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::SYSTEM_MAXIMUM_CELL_VOLTAGE, {78});
+ EXPECT_MODBUS_READ(12,
+ true,
+ BatteryRegisters::DIAGNOSTICS_SHUTDOWNS_DUE_TO_ERROR,
+ {79});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HISTORY_MIN_CELL_VOLTAGE, {80});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::HISTORY_MAX_CELL_VOLTAGE, {81});
+ EXPECT_MODBUS_READ(12, false, BatteryRegisters::MODE, {82});
+ EXPECT_MODBUS_READ(12, true, BatteryRegisters::BALANCER_STATUS, {83});
+
+ BatteryData data = driver.readBatteryData();
+
+ ASSERT_EQ(23, data.battery_power);
+ ASSERT_NEAR(0.24, data.battery_voltage, 1e-3);
+ ASSERT_NEAR(0.25, data.starter_battery_voltage, 1e-3);
+ ASSERT_NEAR(2.6, data.current, 1e-3);
+ ASSERT_NEAR(2.7, data.battery_temperature.getCelsius(), 1e-3);
+ ASSERT_NEAR(0.28, data.mid_point_voltage, 1e-3);
+ ASSERT_NEAR(0.29, data.mid_point_deviation, 1e-3);
+ ASSERT_NEAR(300.0, data.consumed_amphours, 1e-3);
+ ASSERT_NEAR(3.1, data.state_of_charge, 1e-3);
+ ASSERT_EQ(32, data.relay_status);
+ ASSERT_NEAR(330.0, data.deepest_discharge, 1e-3);
+ ASSERT_NEAR(340.0, data.last_discharge, 1e-3);
+ ASSERT_NEAR(350.0, data.average_discharge, 1e-3);
+ ASSERT_EQ(36, data.charge_cycles);
+ ASSERT_EQ(37, data.full_discharges);
+ ASSERT_NEAR(380.0, data.total_ah_drawn, 1e-3);
+ ASSERT_NEAR(0.39, data.minimum_voltage, 1e-3);
+ ASSERT_NEAR(0.40, data.maximum_voltage, 1e-3);
+ ASSERT_NEAR(4100.0, data.time_since_last_full_charge.toSeconds(), 1e-3);
+ ASSERT_EQ(42, data.automatic_syncs);
+ ASSERT_EQ(43, data.low_voltage_alarms);
+ ASSERT_EQ(44, data.high_voltage_alarms);
+ ASSERT_EQ(45, data.low_starter_voltage_alarms);
+ ASSERT_EQ(46, data.high_starter_voltage_alarms);
+ ASSERT_NEAR(0.47, data.minimum_starter_voltage, 1e-3);
+ ASSERT_NEAR(0.48, data.maximum_starter_voltage, 1e-3);
+ ASSERT_EQ(49, data.low_fused_voltage_alarms);
+ ASSERT_EQ(50, data.high_fused_voltage_alarms);
+ ASSERT_NEAR(0.51, data.minimum_fused_voltage, 1e-3);
+ ASSERT_NEAR(0.52, data.maximum_fused_voltage, 1e-3);
+ ASSERT_NEAR(5.3, data.discharged_energy, 1e-3);
+ ASSERT_NEAR(5.4, data.charged_energy, 1e-3);
+ ASSERT_NEAR(5500.0, data.time_to_go.toSeconds(), 1e-3);
+ ASSERT_NEAR(5.6, data.state_of_health, 1e-3);
+ ASSERT_NEAR(5.7, data.max_charge_voltage, 1e-3);
+ ASSERT_NEAR(5.8, data.min_discharge_voltage, 1e-3);
+ ASSERT_NEAR(5.9, data.max_charge_current, 1e-3);
+ ASSERT_NEAR(6.0, data.max_discharge_current, 1e-3);
+ ASSERT_NEAR(6.1, data.capacity, 1e-3);
+
+ ASSERT_EQ(base::Time::fromSeconds(62), data.diagnostics_errors[0].time);
+ ASSERT_EQ(static_cast(63),
+ data.diagnostics_errors[0].error);
+ ASSERT_EQ(base::Time::fromSeconds(64), data.diagnostics_errors[1].time);
+ ASSERT_EQ(static_cast(65),
+ data.diagnostics_errors[1].error);
+ ASSERT_EQ(base::Time::fromSeconds(66), data.diagnostics_errors[2].time);
+ ASSERT_EQ(static_cast(67),
+ data.diagnostics_errors[2].error);
+ ASSERT_EQ(base::Time::fromSeconds(68), data.diagnostics_errors[3].time);
+ ASSERT_EQ(static_cast(69),
+ data.diagnostics_errors[3].error);
+
+ ASSERT_NEAR(7.0, data.minimum_cell_temperature.getCelsius(), 1e-3);
+ ASSERT_NEAR(7.1, data.maximum_cell_temperature.getCelsius(), 1e-3);
+ ASSERT_NEAR(72.0, data.consumed_amphours_1, 1e-3);
+ ASSERT_EQ(static_cast(73), data.state);
+ ASSERT_EQ(static_cast(74), data.error_code);
+ ASSERT_EQ(75 == 1, data.system_switch);
+ ASSERT_EQ(76 == 1, data.balancing);
+ ASSERT_NEAR(0.77, data.system_minimum_cell_voltage, 1e-3);
+ ASSERT_NEAR(0.78, data.system_maximum_cell_voltage, 1e-3);
+ ASSERT_EQ(79, data.diagnostics_shutdowns_due_to_error);
+ ASSERT_NEAR(0.80, data.historical_min_cell_voltage, 1e-3);
+ ASSERT_NEAR(0.81, data.historical_max_cell_voltage, 1e-3);
+ ASSERT_EQ(static_cast(82), data.mode);
+ ASSERT_EQ(static_cast(83), data.balancer_status);
+}
diff --git a/test/test_Dummy.cpp b/test/test_Dummy.cpp
deleted file mode 100644
index 11e4fa6..0000000
--- a/test/test_Dummy.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include
-#include
-
-using namespace power_victron;
-
-BOOST_AUTO_TEST_CASE(it_should_not_crash_when_welcome_is_called)
-{
- power_victron::DummyClass dummy;
- dummy.welcome();
-}