Merge branch 'develop' into rdavis/PHX3_CRAH_LIEBERT_80_SLAB_TCP

This commit is contained in:
Emmanuel HC
2025-11-04 08:27:14 -06:00
committed by GitHub
53 changed files with 2228 additions and 1387 deletions

View File

@@ -1,5 +1,4 @@
; PlatformIO Project Configuration File ; PlatformIO Project Configuration File
;
; Build options: build flags, source filter ; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags ; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages ; Library options: dependencies, extra library storages
@@ -37,6 +36,13 @@ extends = common_env_options
build_flags = -D USE_MODBUS_IP ;Importat configuration, this flags is used to configure the program build_flags = -D USE_MODBUS_IP ;Importat configuration, this flags is used to configure the program
build_src_filter = -<*> +<Base_TCP> ;Add the specific folder path here build_src_filter = -<*> +<Base_TCP> ;Add the specific folder path here
;---------------------------------------------------------------------------------------------------- ;----------------------------------------------------------------------------------------------------
[env:CRAH_PETRA_PAHHC_600_C6_TCP]
platform = espressif32
board = dfrobot_firebeetle2_esp32e
extends = common_env_options
build_flags = -D USE_MODBUS_IP
build_src_filter = -<*> +<BMS/CRAH/CRAH_PETRA_PAHHC_600_C6_TCP>
[env:POD_MBB_Power_Meter_TCP] [env:POD_MBB_Power_Meter_TCP]
platform = espressif32 platform = espressif32
board = dfrobot_firebeetle2_esp32e board = dfrobot_firebeetle2_esp32e
@@ -212,4 +218,11 @@ platform = espressif32
board = dfrobot_firebeetle2_esp32e board = dfrobot_firebeetle2_esp32e
extends = common_env_options extends = common_env_options
build_flags = -D USE_MODBUS_IP build_flags = -D USE_MODBUS_IP
build_src_filter = -<*> +<BMS/CRAH/PHX3_CRAH_LIEBERT_80_SLAB_TCP> build_src_filter = -<*> +<BMS/CRAH/PHX3_CRAH_LIEBERT_80_SLAB_TCP>
[env:HUM_DriSteem_RTS_RX36_TCP]
platform = espressif32
board = dfrobot_firebeetle2_esp32e
extends = common_env_options
build_flags = -D USE_MODBUS_IP
build_src_filter = -<*> +<BMS/HUM/HUM_DriSteem_RTS_RX36_TCP>

View File

@@ -1,16 +1,12 @@
# CHILLER YORK YVAA 0428IOK46BAVTXX TCP # CHILLER YORK YVAA 0428IOK46BAVTXX TCP
## Brief Introduction ## Brief Introduction
Chiller receives Chiller Temp SP and Enable from PLC. The Supply Temp will ramp to Chiller Temp SP in Run Mode.
*** NOTE! *** Alarms are also simulated via Modscan, though those signals will be internal to Chiller.
This code has not been verified with Chiller and Chiller Manager PLC program. Hard IO points simulated with Modscan: Sys 1 Alarm, Sys 2 Alarm.
It is a best-guess based on a preliminary review of Chiller PLC program, but Chiller Status is sent back to PLC.
has yet to be fully vetted and local tested with PLC programs. In practice, all Modbus points are for monitoring only and go to Ignition - not sent to PLC.
For the sake of simulation, some hard IO points (simulated as Modbus points) will go back to PLC for feedback or will be sent from PLC to Arduino.
Chiller receives Temp SP and Enable from PLC (Modscan)
Alarms are also simulated via Modscan, though those signals will be internal to Chiller
Many hard IO points are simulated using Modscan.
Assumes all Modbus points are for monitoring only and go to Ignition - not sent to PLC
## List of Equipment ## List of Equipment
This cofiguration has been used for these models: This cofiguration has been used for these models:
@@ -24,20 +20,51 @@ The code is written for an ESP8266/ESP32-style microcontroller with WiFi capabil
--- ---
## States and Strategies ## States and Strategies
Updates Alarms States. If any active alarms --> FailState Updates Alarms States. Only the Sys 1 Fan Fault or Sys 2 Fan Fault will send unit --> FailState
Sys 1 Alarm, Sys 2 Alarm, and General Alarm will annunciate only, will not stop the unit (this is an assumption the program follows, may differ in field).
Updates Free Cooling Mode: Free Cooling Mode is activated using a coil, for simulation purposes only. Updates Free Cooling Mode: Free Cooling Mode is activated using a coil, for simulation purposes only.
Modbus points are simulated, mostly with a SingleValue strategy for image verification in Ignition. Modbus points are simulated, mostly with a SingleValue strategy for image verification in Ignition.
While in RunningState, the Supply Temp dynamically ramps to the Supply Temp SP sent from PLC (Modscan) While in RunningState, the Supply Temp dynamically ramps to the Supply Temp SP sent from PLC (or Modscan)
The CHW In and CHW Out temperature values also dynamically ramp to match the Return and Supply Temps. The CHW In and CHW Out temperature values also dynamically ramp to match the Return and Supply Temps.
### Standby State ### Standby State
* **Chiller Status**: set to 0 * **Chiller Status**: set to 0
* **Operational Code**: set to 77 * **Operational Code**: set to 77
* **Chiller Start Command**: set to 0 * **Chiller Start Command**: set to 0
Supply Temp = 80 +/- 1
Return Temp = 80 +/- 1
System CHW Out = 80 +/- 1
System CHW In = 80 +/- 1
Ambient Temp = 1-- +/- 1
Sys 1, 2 Oil Pressure = 420 +/- 1
Sys 1, 2 Suction Pressure = 70 +/- 1
Sys 1, 2 Discharge Pressure = 70 +/- 1
Sys 1, 2 Condenser Temp = 124 +/- 1
### Running State ### Running State
* **Chiller status**: set to 1 * **Chiller status**: set to 1
* **Supply Temperature**: **Ramp Strategy** ramps to Temp Setpoint from PLC (Modscan) * **Operational Code**: set to 78 (running)
* **Supply Temperature**: **Ramp Strategy** ramps to Chiller Temp Setpoint from PLC (Modscan)
Supply Temp dynamically ramps to Chiller Temp Setpoint as sent from PLC (or Modscan)
Return Temp sawStrategy (79-83)
System CHW Out dynamically ramps to follow Supply Temp
System CHW In dynamically ramps to follow Return Temp
Ambient Temp = 1-- +/- 1
Sys 1, 2 Oil Pressure = 450 +/- 5
Sys 1, 2 Suction Pressure = 70 +/- 2
Sys 1, 2 Discharge Pressure = 375 +/- 4
Sys 1, 2 Compressor Pct FLA = 93 +/- 2
Sys 1, 2 Condenser Temp = 125 +/- 5
Sys 1 Fan kW = 35 +/- 2
Sys 2 Fan kW = 23 +/- 2
Sys 1 Compressor kW = 304 +/- 5
Sys 2 Compressor kW = 198 +/- 5
### Fail State ### Fail State
* **Chiller Status**: set to 0 All values match that of Standby State.
The difference is in Fail State, if a Start Command is sent it will not start the Chiller.
All faults must be cleared, then unit transitions to Standby State.
* **Chiller Status**: set to 0
* **Operational Code**: set to 77
* **Chiller Start Command**: set to 0
All analog values same as in Standby State

View File

@@ -32,13 +32,15 @@
* @brief Updates Alarms states * @brief Updates Alarms states
* *
* This function will update the Alarm status DI bits according to the Alarm Commands from Coils (Modscan) * This function will update the Alarm status DI bits according to the Alarm Commands from Coils (Modscan)
* The appropriate Fault Code will also be set to 56 (Condenser Fan VSD Warning) * The appropriate Fault Code will also be set to 56 (Condenser Fan VSD Warning).
* Also updates the General Alarm bit. If any alarms are active, General Alarm --> 1, else 0.
* *
* This is a function used in the update() of the Standby, Running, and Fail States. * This is a function used in the update() of the Standby, Running, and Fail States.
* *
*/ */
void updateAlarms(Equipment<ModbusRTU>* equipment){ void updateAlarms(Equipment<ModbusRTU>* equipment){
// Updates Sys 1, 2 Fan Fault Alarms with associated Fault Code
Modbus_Point<ModbusRTU>* Sys1FanAlarmCommand = equipment->getModbus_Point("Sys 1 Fan Fault ON"); Modbus_Point<ModbusRTU>* Sys1FanAlarmCommand = equipment->getModbus_Point("Sys 1 Fan Fault ON");
Modbus_Point<ModbusRTU>* Sys2FanAlarmCommand = equipment->getModbus_Point("Sys 2 Fan Fault ON"); Modbus_Point<ModbusRTU>* Sys2FanAlarmCommand = equipment->getModbus_Point("Sys 2 Fan Fault ON");
Modbus_Point<ModbusRTU>* Sys1FanAlarm = equipment->getModbus_Point("Sys 1 Fan Fault Alarm"); Modbus_Point<ModbusRTU>* Sys1FanAlarm = equipment->getModbus_Point("Sys 1 Fan Fault Alarm");
@@ -57,6 +59,20 @@ void updateAlarms(Equipment<ModbusRTU>* equipment){
} }
else equipment->setModbus_Point("Sys 2 Fault Code", 0); else equipment->setModbus_Point("Sys 2 Fault Code", 0);
} }
// Update General Alarm (if any Alarm is active, make general alarm active)
const std::vector<std::string> alarmDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm"
};
int numAlarms = 0;
for (int i =0; i < alarmDescriptions.size(); ++i) {
Modbus_Point<ModbusRTU>* alarmPoint = equipment->getModbus_Point(alarmDescriptions[i]);
if (alarmPoint) {
if (alarmPoint->getValue() == 1) numAlarms++;
}
}
if (numAlarms >= 1) equipment->setModbus_Point("General Alarm", 1);
else equipment->setModbus_Point("General Alarm", 0);
} }
/** /**
@@ -74,12 +90,6 @@ void updateFreeCooling(Equipment<ModbusRTU>* equipment){
Modbus_Point<ModbusRTU>* FreeCoolingCommand = equipment->getModbus_Point("Free Cooling Mode ON"); Modbus_Point<ModbusRTU>* FreeCoolingCommand = equipment->getModbus_Point("Free Cooling Mode ON");
Modbus_Point<ModbusRTU>* FreeCoolingMode = equipment->getModbus_Point("Free Cooling Mode"); Modbus_Point<ModbusRTU>* FreeCoolingMode = equipment->getModbus_Point("Free Cooling Mode");
Modbus_Point<ModbusRTU>* FreeCoolingValve = equipment->getModbus_Point("Free Cooling Valve"); Modbus_Point<ModbusRTU>* FreeCoolingValve = equipment->getModbus_Point("Free Cooling Valve");
if (FreeCoolingCommand->getValue() == 1) { FreeCoolingMode->setValue(FreeCoolingCommand->getValue());
FreeCoolingMode->setValue(1); FreeCoolingValve->setValue(FreeCoolingCommand->getValue());
FreeCoolingValve->setValue(1);
}
else {
FreeCoolingMode->setValue(0);
FreeCoolingValve->setValue(0);
}
} }

View File

@@ -6,6 +6,7 @@
* *
* This file contains the implementation for the FailState, which defines * This file contains the implementation for the FailState, which defines
* the behavior of the equipment when it has entered a fault condition. * the behavior of the equipment when it has entered a fault condition.
* The unit enters Fail State if Sys 1 Fan Fault Alarm or Sys 2 Fan Fault Alarm is active.
*/ */
#include "ModbusPoints/Modbus_Point.h" #include "ModbusPoints/Modbus_Point.h"
#include "Equipment/Equipment.h" #include "Equipment/Equipment.h"
@@ -29,15 +30,31 @@
* @brief Constructs a new FailState object. * @brief Constructs a new FailState object.
* *
* This constructor receives a list of alarm descriptions and creates strategies * This constructor receives a list of alarm descriptions and creates strategies
* to set the Compressor and Fan kW to 0. * to set the unit back into an idle, de-energized state.
* *
* @param activeAlarms A vector of strings, where each string is the * @param activeFaults A vector of strings, where each string is the
* description of a Modbus point to be set as an active alarm. * description of the currently active faults.
*/ */
template<> template<>
FailState<ModbusRTU>::FailState(const std::vector<std::string>& activeAlarms) { FailState<ModbusRTU>::FailState(const std::vector<std::string>& activeFaults) {
addStrategy("Supply Temp", new SingleValueStrategy(80.0f, 1.0f, 1000));
addStrategy("Return Temp", new SingleValueStrategy(80.0f, 1.0f, 1000));
addStrategy("Ambient Temp", new SingleValueStrategy(100.0f, 1.0f, 1000));
addStrategy("System CHW Out", new SingleValueStrategy(80.0f, 1.0f, 1000));
addStrategy("System CHW In", new SingleValueStrategy(80.0f, 1.0f, 1000));
addStrategy("Sys 1 Condenser Temp", new SingleValueStrategy(124.0f, 1.0f, 1000));
addStrategy("Sys 2 Condenser Temp", new SingleValueStrategy(124.0f, 1.0f, 1000));
addStrategy("Sys 1 Oil Pressure", new SingleValueStrategy(420.0f, 1.0f, 1000));
addStrategy("Sys 2 Oil Pressure", new SingleValueStrategy(420.0f, 1.0f, 1000));
addStrategy("Sys 1 Suction Pressure", new SingleValueStrategy(70.0f, 1.0f, 1000));
addStrategy("Sys 2 Suction Pressure", new SingleValueStrategy(70.0f, 1.0f, 1000));
addStrategy("Sys 1 Discharge Pressure", new SingleValueStrategy(70.0f, 1.0f, 1000));
addStrategy("Sys 2 Discharge Pressure", new SingleValueStrategy(70.0f, 1.0f, 1000));
addStrategy("Sys 1 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 2 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 2 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Local Leaving Temp Setpoint", new SingleValueStrategy(70.0f, 0.0f, 1000));
addStrategy("VSD Output Frequency", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 1 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 2 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 2 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
@@ -48,33 +65,44 @@ FailState<ModbusRTU>::FailState(const std::vector<std::string>& activeAlarms) {
* @brief Executes the fail state's logic for one update cycle. * @brief Executes the fail state's logic for one update cycle.
* *
* This method first updates all alarms states and Free Cooling Mode (for ease of testing). * This method first updates all alarms states and Free Cooling Mode (for ease of testing).
* If all alarms have been cleared --> StandbyState. * If all faults have been cleared --> StandbyState.
* If alarms are still active, ensures the Chiller Start Command remains at 0. * If faults are still active, ensures the Chiller Start Command remains at 0.
* *
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr. * @return A pointer to a new State if a transition should occur, otherwise nullptr.
*/ */
template<> template<>
State<ModbusRTU>* FailState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) { State<ModbusRTU>* FailState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) {
// Update alarms states, Free Cooling mode, Freeze Protection Mode // Update alarms states, Free Cooling mode
updateAlarms(equipment); updateAlarms(equipment);
updateFreeCooling(equipment); updateFreeCooling(equipment);
const std::vector<std::string> alarmDescriptions = { const std::vector<std::string> FaultDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm",
}; };
// If no alarms active --> send to StandbyState() // If no faults active --> send to StandbyState()
bool alarms_active = false; bool faults_active = false;
for (const auto& desc : alarmDescriptions) { for (const auto& desc : FaultDescriptions) {
Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc); Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc);
if (point->getValue() == 1) { if (point->getValue() == 1) {
alarms_active = true; faults_active = true;
} }
} }
if (!alarms_active) return new StandbyState<ModbusRTU>(); if (!faults_active) return new StandbyState<ModbusRTU>();
setPointValue(equipment, "Chiller Start Command", 0); setPointValue(equipment, "Chiller Start Command", 0);
// Update Operational Code depending on Free Cooling Mode
int freeCoolingState = getPointValue(equipment, "Free Cooling Mode ON");
if (freeCoolingState == 1){
setPointValue(equipment, "Sys 1 Operational Code", 82);
setPointValue(equipment, "Sys 2 Operational Code", 82);
}
else{
setPointValue(equipment, "Sys 1 Operational Code", 77);
setPointValue(equipment, "Sys 2 Operational Code", 77);
}
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -60,11 +60,11 @@ RunningState<ModbusRTU>::RunningState() {
addStrategy("Sys 1 Run Hours", new TotalizerStrategy(1000)); addStrategy("Sys 1 Run Hours", new TotalizerStrategy(1000));
addStrategy("Sys 2 Run Hours", new TotalizerStrategy(1000)); addStrategy("Sys 2 Run Hours", new TotalizerStrategy(1000));
addStrategy("Local Leaving Temp Setpoint", new SingleValueStrategy(70.0f, 0.0f, 1000)); addStrategy("Local Leaving Temp Setpoint", new SingleValueStrategy(70.0f, 0.0f, 1000));
addStrategy("VSD Output Frequency", new SingleValueStrategy(59.0f, 1.0f, 1000));
addStrategy("Sys 1 Fan KW", new SingleValueStrategy(35.0f, 2.0f, 1000)); addStrategy("Sys 1 Fan KW", new SingleValueStrategy(35.0f, 2.0f, 1000));
addStrategy("Sys 2 Fan KW", new SingleValueStrategy(23.0f, 2.0f, 1000)); addStrategy("Sys 2 Fan KW", new SingleValueStrategy(23.0f, 2.0f, 1000));
addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(304.0f, 5.0f, 1000)); addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(304.0f, 5.0f, 1000));
addStrategy("Sys 2 Compressor KW", new SingleValueStrategy(198.0f, 5.0f, 1000)); addStrategy("Sys 2 Compressor KW", new SingleValueStrategy(198.0f, 5.0f, 1000));
} }
/** /**
@@ -88,23 +88,23 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
updateAlarms(equipment); updateAlarms(equipment);
updateFreeCooling(equipment); updateFreeCooling(equipment);
std::vector<std::string> activeAlarmsDescriptions = {}; std::vector<std::string> activeFaultDescriptions = {};
const std::vector<std::string> alarmDescriptions = { const std::vector<std::string> FaultDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm"
}; };
// Loop through alarms, create array of active alarms and send to FailState if any alarms are active // Loop through faults, create array of active faults and send to FailState if any faults are active
bool alarms_active = false; bool faults_active = false;
for (const auto& desc : alarmDescriptions) { for (const auto& desc : FaultDescriptions) {
Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc); Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc);
if (point->getValue() == 1) { if (point->getValue() == 1) {
activeAlarmsDescriptions.push_back(desc); activeFaultDescriptions.push_back(desc);
alarms_active = true; faults_active = true;
} }
} }
if (alarms_active) return new FailState<ModbusRTU>(activeAlarmsDescriptions); if (faults_active) return new FailState<ModbusRTU>(activeFaultDescriptions);
// If no alarms active and Start Command = 0--> send to StandbyState() // If no faults active and Start Command = 0--> send to StandbyState()
int Chiller_Enable = getPointValue(equipment, "Chiller Start Command"); // Modscan COIL 1 int Chiller_Enable = getPointValue(equipment, "Chiller Start Command"); // Modscan COIL 1
if (Chiller_Enable == 0){ if (Chiller_Enable == 0){
return new StandbyState<ModbusRTU>(); return new StandbyState<ModbusRTU>();
@@ -124,6 +124,17 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
static_cast<RampStrategy*>(CHW_In_strat)->setTarget(returnTemp); static_cast<RampStrategy*>(CHW_In_strat)->setTarget(returnTemp);
} }
// Update Operational Code depending on Free Cooling Mode
int freeCoolingState = getPointValue(equipment, "Free Cooling Mode ON");
if (freeCoolingState == 1){
setPointValue(equipment, "Sys 1 Operational Code", 82);
setPointValue(equipment, "Sys 2 Operational Code", 82);
}
else{
setPointValue(equipment, "Sys 1 Operational Code", 78);
setPointValue(equipment, "Sys 2 Operational Code", 78);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -55,6 +55,7 @@ StandbyState<ModbusRTU>::StandbyState() {
addStrategy("Sys 1 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 2 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 2 Compressor Pct FLA", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Local Leaving Temp Setpoint", new SingleValueStrategy(70.0f, 0.0f, 1000)); addStrategy("Local Leaving Temp Setpoint", new SingleValueStrategy(70.0f, 0.0f, 1000));
addStrategy("VSD Output Frequency", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 1 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 2 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 2 Fan KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Sys 1 Compressor KW", new SingleValueStrategy(0.0f, 0.0f, 1000));
@@ -82,7 +83,7 @@ State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
std::vector<std::string> activeAlarmsDescriptions = {}; std::vector<std::string> activeAlarmsDescriptions = {};
const std::vector<std::string> alarmDescriptions = { const std::vector<std::string> alarmDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm"
}; };
// Loop through alarms, create array of active alarms and send to FailState if any alarms are active // Loop through alarms, create array of active alarms and send to FailState if any alarms are active
@@ -102,6 +103,17 @@ State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
return new RunningState<ModbusRTU>(); return new RunningState<ModbusRTU>();
} }
// Update Operational Code depending on Free Cooling Mode
int freeCoolingState = getPointValue(equipment, "Free Cooling Mode ON");
if (freeCoolingState == 1){
setPointValue(equipment, "Sys 1 Operational Code", 82);
setPointValue(equipment, "Sys 2 Operational Code", 82);
}
else{
setPointValue(equipment, "Sys 1 Operational Code", 77);
setPointValue(equipment, "Sys 2 Operational Code", 77);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -54,54 +54,58 @@
*/ */
modbusMap mb_map[] = modbusMap mb_map[] =
{ {
{COIL, 0, 0, "Chiller Start Command"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only {COIL, 0, 0, "Chiller Start Command"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only. Signal should come from PLC.
{COIL, 1, 0, "Sys 1 Alarm"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only {COIL, 1, 0, "Sys 1 Alarm"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only --> INDICATION ONLY (assumption)
{COIL, 2, 0, "Sys 2 Alarm"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only {COIL, 2, 0, "Sys 2 Alarm"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only --> INDICATION ONLY (assumption)
{COIL, 3, 0, "Sys 1 Fan Fault ON"}, // Use in Modscan - Used for Arduino simulation only {COIL, 3, 0, "Sys 1 Fan Fault ON"}, // Use in Modscan - Used for Arduino simulation only --> FAILSTATE (assumption)
{COIL, 4, 0, "Sys 2 Fan Fault ON"}, // Use in Modscan - Used for Arduino simulation only {COIL, 4, 0, "Sys 2 Fan Fault ON"}, // Use in Modscan - Used for Arduino simulation only --> FAILSTATE (assumption)
{COIL, 5, 0, "Free Cooling Mode ON"}, // Use in Modscan - Used for Arduino simulation only {COIL, 5, 0, "Free Cooling Mode ON"}, // Use in Modscan - Used for Arduino simulation only
{DI, 0, 0, "Sys 1 Fan Fault Alarm"}, {DI, 65, 0, "General Alarm"}, // if any alarm is active, General Alarm = 1 --> used for INDICATION ONLY (assumption)
{DI, 1, 0, "Sys 2 Fan Fault Alarm"}, {DI, 174, 0, "Sys 1 Fan Fault Alarm"},
{DI, 175, 0, "Sys 2 Fan Fault Alarm"},
{HR, 0, 0, "Chiller Status"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only {IR, 130, 0, "Free Cooling Mode"},
{HR, 1, 0, "Chiller Temp Setpoint"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only {IR, 165, 0, "Free Cooling Valve"},
{HR, 2, 0, "Supply Temp"}, // Use in Modscan - Hard IO in SCP (PICS?), Used for Arduino simulation only
{HR, 3, 0, "Return Temp"}, // Use in Modscan - Hard IO in SCP (PICS?), Used for Arduino simulation only
{HR, 4, 70, "System CHW Out"}, {HR, 0, 0, "Chiller Status"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only
{HR, 5, 70, "System CHW In"}, {HR, 1, 0, "Chiller Temp Setpoint"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only
{HR, 7, 0, "Sys 1 Condenser Temp"}, {HR, 2, 0, "Supply Temp"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only
{HR, 9, 0, "Ambient Temp"}, {HR, 3, 0, "Return Temp"}, // Use in Modscan - Hard IO in SCP, Used for Arduino simulation only
{HR, 11, 0, "Sys 1 Oil Pressure"}, {HR, 4, 70, "System CHW Out"},
{HR, 12, 0, "Sys 1 Suction Pressure"}, {HR, 5, 70, "System CHW In"},
{HR, 13, 0, "Sys 1 Discharge Pressure"}, {HR_10x, 7, 0, "Sys 1 Condenser Temp"},
{HR, 14, 0, "Sys 1 Compressor Pct FLA"}, {HR_10x, 9, 0, "Ambient Temp"},
{HR, 15, 0, "Sys 1 Run Hours"},
{HR, 16, 0, "Sys 1 Starts"}, {HR_10x, 11, 0, "Sys 1 Oil Pressure"},
{HR_10x, 12, 0, "Sys 1 Suction Pressure"},
{HR_10x, 13, 0, "Sys 1 Discharge Pressure"},
{HR_10x, 14, 0, "Sys 1 Compressor Pct FLA"},
{HR, 15, 0, "Sys 1 Run Hours"},
{HR, 16, 0, "Sys 1 Starts"},
{HR, 20, 0, "Sys 2 Oil Pressure"}, {HR_10x, 20, 0, "Sys 2 Oil Pressure"},
{HR, 21, 0, "Sys 2 Suction Pressure"}, {HR_10x, 21, 0, "Sys 2 Suction Pressure"},
{HR, 22, 0, "Sys 2 Discharge Pressure"}, {HR_10x, 22, 0, "Sys 2 Discharge Pressure"},
{HR, 23, 0, "Sys 2 Compressor Pct FLA"}, {HR_10x, 23, 0, "Sys 2 Compressor Pct FLA"},
{HR, 24, 0, "Sys 2 Run Hours"}, {HR, 24, 0, "Sys 2 Run Hours"},
{HR, 25, 0, "Sys 2 Starts"}, {HR, 25, 0, "Sys 2 Starts"},
{HR, 29, 77, "Sys 1 Operational Code"}, {HR_10x, 26, 0, "VSD Output Frequency"},
{HR, 30, 0, "Sys 1 Fault Code"},
{HR, 31, 77, "Sys 2 Operational Code"},
{HR, 32, 0, "Sys 2 Fault Code"},
{HR, 39, 0, "Local Leaving Temp Setpoint"}, {HR, 29, 77, "Sys 1 Operational Code"}, // 77:not running, 78:running, 82:free cooling
{HR, 30, 0, "Sys 1 Fault Code"}, // 56:condenser fan VSD warning
{HR, 31, 77, "Sys 2 Operational Code"}, // 77:not running, 78:running, 82:free cooling
{HR, 32, 0, "Sys 2 Fault Code"}, // 56:condenser fan VSD warning
{HR, 40, 0, "Sys 1 Fan KW"}, {HR, 39, 0, "Local Leaving Temp Setpoint"},
{HR, 41, 0, "Sys 1 Compressor KW"},
{HR, 42, 0, "Sys 2 Fan KW"}, {HR_10x, 49, 0, "Sys 2 Condenser Temp"},
{HR, 43, 0, "Sys 2 Compressor KW"}, {HR_10x, 140, 0, "Sys 1 Fan KW"},
{HR, 49, 0, "Sys 2 Condenser Temp"}, {HR_10x, 141, 0, "Sys 1 Compressor KW"},
{HR, 50, 0, "Free Cooling Mode"}, {HR_10x, 142, 0, "Sys 2 Fan KW"},
{HR, 51, 0, "Free Cooling Valve"}, {HR_10x, 143, 0, "Sys 2 Compressor KW"},
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.

View File

@@ -1,11 +1,11 @@
/** /**
* @file main.cpp * @file main.cpp
* @brief Main execution program for the Daikin Chiller (RTU) Emulator. * @brief Main execution program for the York YVAA Chiller (RTU) Emulator.
* @author Emmanuel Hernandez Cruz * @author Emmanuel Hernandez Cruz, Robert J. Davis
* @date 2025-09-02 * @date 2025-09-02
* *
* @details This file contains the main execution program for an Arduino-based * @details This file contains the main execution program for an Arduino-based
* emulator of a Daikin Chiller unit. The program communicates via the * emulator of a York YVAA Chiller unit. The program communicates via the
* Modbus RTU protocol over a serial connection. * Modbus RTU protocol over a serial connection.
* *
* The setup() function initializes the following: * The setup() function initializes the following:

View File

@@ -38,16 +38,26 @@
*/ */
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("CW Valve Position", new PIDStrategy("RAT Setpoint", 1000, "RAT")); addStrategy("CW Valve Position", new PIDStrategy("SAT Setpoint", 2000, "SAT Reading"));
addStrategy("Operating Hours EC Fan #1", new TotalizerStrategy(10000)); addStrategy("SAT Reading", new SingleValueStrategy(0.0f, 3.0f, 1000));
addStrategy("Operating Hours EC Fan #2", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #1", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #3", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #2", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #4", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #3", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #5", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #4", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #6", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #5", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #7", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #6", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #8", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #7", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #9", new TotalizerStrategy(10000)); addStrategy("Speed EC Fan #8", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #9", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Operating Hours EC Fan #1", new TotalizerStrategy(1100));
addStrategy("Operating Hours EC Fan #2", new TotalizerStrategy(1200));
addStrategy("Operating Hours EC Fan #3", new TotalizerStrategy(1300));
addStrategy("Operating Hours EC Fan #4", new TotalizerStrategy(1250));
addStrategy("Operating Hours EC Fan #5", new TotalizerStrategy(1350));
addStrategy("Operating Hours EC Fan #6", new TotalizerStrategy(1450));
addStrategy("Operating Hours EC Fan #7", new TotalizerStrategy(1150));
addStrategy("Operating Hours EC Fan #8", new TotalizerStrategy(1180));
addStrategy("Operating Hours EC Fan #9", new TotalizerStrategy(1340));
} }
/** /**
@@ -74,63 +84,36 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
Modbus_Point<ModbusIP>* faultCode = equipment->getModbus_Point("Fault Code");
int faultCodeValue = faultCode ? faultCode->getValue() : 0;
switch (faultCodeValue){
case 1:
return new FailState<ModbusIP>({"Alarm SAT Sensor Fault"});
case 2:
return new FailState<ModbusIP>({"Alarm RAH Sensor Fault"});
case 3:
return new FailState<ModbusIP>({"Alarm RAT Sensor Fault"});
case 4:
return new FailState<ModbusIP>({"Alarm Filter DP Sensor Fault"});
case 5:
return new FailState<ModbusIP>({"Alarm Flooding"});
case 6:
return new FailState<ModbusIP>({"Alarm Dirty Filter"});
case 7:
return new FailState<ModbusIP>({"Alarm High RAT"});
case 8:
return new FailState<ModbusIP>({"Alarm Low RAT"});
case 9:
return new FailState<ModbusIP>({"Alarm High SAT"});
case 10:
return new FailState<ModbusIP>({"Alarm Low SAT"});
case 11:
return new FailState<ModbusIP>({"Alarm High RAH"});
case 12:
return new FailState<ModbusIP>({"Alarm Low RAH"});
case 13:
return new FailState<ModbusIP>({"Alarm Phase Failure"});
case 14:
return new FailState<ModbusIP>({"Alarm Condensate Pump"});
case 15:
return new FailState<ModbusIP>({"Alarm Smoke"});
case 16:
return new FailState<ModbusIP>({"Alarm Fire"});
case 17:
return new FailState<ModbusIP>({"Alarm EC Fan #1"});
case 18:
return new FailState<ModbusIP>({"Alarm EC Fan #2"});
case 19:
return new FailState<ModbusIP>({"Alarm EC Fan #3"});
case 20:
return new FailState<ModbusIP>({"Alarm EC Fan #4"});
case 21:
return new FailState<ModbusIP>({"Alarm EC Fan #5"});
case 22:
return new FailState<ModbusIP>({"Alarm EC Fan #6"});
case 23:
return new FailState<ModbusIP>({"Alarm EC Fan #7"});
case 24:
return new FailState<ModbusIP>({"Alarm EC Fan #8"});
case 25:
return new FailState<ModbusIP>({"Alarm EC Fan #9"});
default:
break;
}
float rat = getPointValue(equipment, "RAT");
setPointValue(equipment, "RAT Reading", rat);
float speed = getPointValue(equipment, "Setting EC Fan Speed");
Strategy_Behavior* fan1_rs = getStrategy("Speed EC Fan #1");
static_cast<RampStrategy*>(fan1_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan2_rs = getStrategy("Speed EC Fan #2");
static_cast<RampStrategy*>(fan2_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan3_rs = getStrategy("Speed EC Fan #3");
static_cast<RampStrategy*>(fan3_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan4_rs = getStrategy("Speed EC Fan #4");
static_cast<RampStrategy*>(fan4_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan5_rs = getStrategy("Speed EC Fan #5");
static_cast<RampStrategy*>(fan5_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan6_rs = getStrategy("Speed EC Fan #6");
static_cast<RampStrategy*>(fan6_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan7_rs = getStrategy("Speed EC Fan #7");
static_cast<RampStrategy*>(fan7_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan8_rs = getStrategy("Speed EC Fan #8");
static_cast<RampStrategy*>(fan8_rs)->setTarget(4200.0f * (speed /100.0f));
Strategy_Behavior* fan9_rs = getStrategy("Speed EC Fan #9");
static_cast<RampStrategy*>(fan9_rs)->setTarget(4200.0f * (speed /100.0f));
float value = getPointValue(equipment, "CW Valve Position");
Serial.printf("CW Valve Position: %0.2f\n", value);
float sat_setpoint = getPointValue(equipment, "SAT Setpoint");
Strategy_Behavior* sat_svs = getStrategy("SAT Reading");
static_cast<SingleValueStrategy*>(sat_svs)->setSetpoint(sat_setpoint);
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -21,10 +21,10 @@
* @{ * @{
*/ */
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "wifi_name"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "wifi_password"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(192, 168, 1, 234); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 11); /**< @brief The static IP address for the device. */
IPAddress gateway(192, 168, 1, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;
@@ -60,81 +60,82 @@
*/ */
modbusMap mb_map[] = modbusMap mb_map[] =
{ {
{HR, 15, 0, "State Control"}, //Internal to control from Modscan {HR, 13, 0, "Delta"},
{HR, 16, 0, "Fault Code"}, {HR, 14, 0, "State Control"}, //Internal to control from Modscan
{HR_FLOAT, 18, 0, "RAT"}, //Internal Fault code from Modscan {HR, 15, 0, "Fault Code"},
{HR_FLOAT, 1, 0, "SAT Setpoint"}, {HR_FLOAT, 17, 0, "RAT"}, //Internal Fault code from Modscan
{HR_FLOAT, 681, 0, "RAT Setpoint"}, {HR_FLOAT, 0, 0, "SAT Setpoint"},
{HR_FLOAT, 111, 0, "High RAT Limit"}, {HR_FLOAT, 680, 0, "RAT Setpoint"},
{HR_FLOAT, 114, 0, "Low RAT Limit"}, {HR_FLOAT, 110, 0, "High RAT Limit"},
{HR_FLOAT, 118, 0, "High SAT Limit"}, {HR_FLOAT, 113, 0, "Low RAT Limit"},
{HR_FLOAT, 122, 0, "Low SAT Limit"}, {HR_FLOAT, 117, 0, "High SAT Limit"},
{HR_FLOAT, 685, 0, "High RAH Limit"}, {HR_FLOAT, 121, 0, "Low SAT Limit"},
{HR_FLOAT, 689, 0, "Low RAH Limit"}, {HR_FLOAT, 684, 0, "High RAH Limit"},
{HR, 5, 0, "Setting the EC Fan Max Speed"}, {HR_FLOAT, 688, 0, "Low RAH Limit"},
{HR, 695, 0, "Setting the EC Fan Min Speed"}, {HR, 4, 0, "Setting the EC Fan Max Speed"},
{HR_FLOAT, 693, 0, "Setting Room Temp"}, {HR, 694, 0, "Setting the EC Fan Min Speed"},
{HR, 691, 0, "Setting EC Fan Speed "}, {HR_FLOAT, 692, 0, "Setting Room Temp"},
{DI, 146, 0, "Alarm SAT Sensor Fault"}, {HR_FLOAT, 690, 0, "Setting EC Fan Speed"},
{DI, 1246, 0, "Alarm RAH Sensor Fault"}, {DI, 145, 0, "Alarm SAT Sensor Fault"},
{DI, 1245, 0, "Alarm RAT Sensor Fault"}, {DI, 1245, 0, "Alarm RAH Sensor Fault"},
{DI, 1250, 0, "Alarm Filter DP Sensor Fault"}, {DI, 1244, 0, "Alarm RAT Sensor Fault"},
{DI, 51, 0, "Alarm Flooding"}, {DI, 1249, 0, "Alarm Filter DP Sensor Fault"},
{DI, 1096, 0, "Alarm Dirty Filter"}, {DI, 50, 0, "Alarm Flooding"},
{DI, 1367, 0, "Alarm High RAT"}, {DI, 1095, 0, "Alarm Dirty Filter"},
{DI, 1099, 0, "Alarm Low RAT"}, {DI, 1366, 0, "Alarm High RAT"},
{DI, 118, 0, "Alarm High SAT"}, {DI, 1098, 0, "Alarm Low RAT"},
{DI, 122, 0, "Alarm Low SAT"}, {DI, 117, 0, "Alarm High SAT"},
{DI, 1307, 0, "Alarm High RAH"}, {DI, 121, 0, "Alarm Low SAT"},
{DI, 1308, 0, "Alarm Low RAH"}, {DI, 1306, 0, "Alarm High RAH"},
{DI, 1342, 0, "Alarm Common"}, {DI, 1307, 0, "Alarm Low RAH"},
{DI, 148, 0, "Alarm Phase Failure"}, {DI, 1341, 0, "Alarm Common"},
{DI, 1370, 0, "Alarm Condensate Pump"}, {DI, 147, 0, "Alarm Phase Failure"},
{DI, 1368, 0, "Alarm Smoke"}, {DI, 1369, 0, "Alarm Condensate Pump"},
{DI, 1369, 0, "Alarm Fire"}, {DI, 1367, 0, "Alarm Smoke"},
{DI, 131, 0, "Alarm EC Fan #1"}, {DI, 1368, 0, "Alarm Fire"},
{DI, 132, 0, "Alarm EC Fan #2"}, {DI, 130, 0, "Alarm EC Fan #1"},
{DI, 133, 0, "Alarm EC Fan #3"}, {DI, 131, 0, "Alarm EC Fan #2"},
{DI, 134, 0, "Alarm EC Fan #4"}, {DI, 132, 0, "Alarm EC Fan #3"},
{DI, 135, 0, "Alarm EC Fan #5"}, {DI, 133, 0, "Alarm EC Fan #4"},
{DI, 136, 0, "Alarm EC Fan #6"}, {DI, 134, 0, "Alarm EC Fan #5"},
{DI, 1360, 0, "Alarm EC Fan #7"}, {DI, 135, 0, "Alarm EC Fan #6"},
{DI, 1361, 0, "Alarm EC Fan #8"}, {DI, 1359, 0, "Alarm EC Fan #7"},
{DI, 1362, 0, "Alarm EC Fan #9"}, {DI, 1360, 0, "Alarm EC Fan #8"},
{DI, 138, 0, "Run Status EC Fan #1"}, {DI, 1361, 0, "Alarm EC Fan #9"},
{DI, 139, 0, "Run Status EC Fan #2"}, {DI, 137, 0, "Run Status EC Fan #1"},
{DI, 140, 0, "Run Status EC Fan #3"}, {DI, 138, 0, "Run Status EC Fan #2"},
{DI, 141, 0, "Run Status EC Fan #4"}, {DI, 139, 0, "Run Status EC Fan #3"},
{DI, 142, 0, "Run Status EC Fan #5"}, {DI, 140, 0, "Run Status EC Fan #4"},
{DI, 143, 0, "Run Status EC Fan #6"}, {DI, 141, 0, "Run Status EC Fan #5"},
{DI, 1363, 0, "Run Status EC Fan #7"}, {DI, 142, 0, "Run Status EC Fan #6"},
{DI, 1364, 0, "Run Status EC Fan #8"}, {DI, 1362, 0, "Run Status EC Fan #7"},
{DI, 1365, 0, "Run Status EC Fan #9"}, {DI, 1363, 0, "Run Status EC Fan #8"},
{IR_FLOAT, 99, 0, "SAT Reading"}, {DI, 1364, 0, "Run Status EC Fan #9"},
{IR_FLOAT, 70, 0, "RAH Reading"}, {IR_FLOAT, 98, 0, "SAT Reading"},
{IR_FLOAT, 101, 0, "RAT Reading"}, {IR_FLOAT, 69, 0, "RAH Reading"},
{IR_FLOAT, 106, 0, "Filter DP Reading"}, {IR_FLOAT, 100, 0, "RAT Reading"},
{IR_FLOAT, 496, 0, "CW Valve Position"}, {IR_FLOAT, 105, 0, "Filter DP Reading"},
{IR, 53, 0, "Speed EC Fan #1"}, {IR_FLOAT, 495, 0, "CW Valve Position"},
{IR, 228, 0, "Speed EC Fan #2"}, {IR, 52, 0, "Speed EC Fan #1"},
{IR, 229, 0, "Speed EC Fan #3"}, {IR, 227, 0, "Speed EC Fan #2"},
{IR, 230, 0, "Speed EC Fan #4"}, {IR, 228, 0, "Speed EC Fan #3"},
{IR, 231, 0, "Speed EC Fan #5"}, {IR, 229, 0, "Speed EC Fan #4"},
{IR, 232, 0, "Speed EC Fan #6"}, {IR, 230, 0, "Speed EC Fan #5"},
{IR, 678, 0, "Speed EC Fan #7"}, {IR, 231, 0, "Speed EC Fan #6"},
{IR, 679, 0, "Speed EC Fan #8"}, {IR, 677, 0, "Speed EC Fan #7"},
{IR, 680, 0, "Speed EC Fan #9"}, {IR, 678, 0, "Speed EC Fan #8"},
{IR, 274, 0, "Operating Hours EC Fan #1"}, {IR, 679, 0, "Speed EC Fan #9"},
{IR, 233, 0, "Operating Hours EC Fan #2"}, {IR, 273, 0, "Operating Hours EC Fan #1"},
{IR, 244, 0, "Operating Hours EC Fan #3"}, {IR, 232, 0, "Operating Hours EC Fan #2"},
{IR, 235, 0, "Operating Hours EC Fan #4"}, {IR, 243, 0, "Operating Hours EC Fan #3"},
{IR, 236, 0, "Operating Hours EC Fan #5"}, {IR, 234, 0, "Operating Hours EC Fan #4"},
{IR, 245, 0, "Operating Hours EC Fan #6"}, {IR, 235, 0, "Operating Hours EC Fan #5"},
{IR, 486, 0, "Operating Hours EC Fan #7"}, {IR, 244, 0, "Operating Hours EC Fan #6"},
{IR, 487, 0, "Operating Hours EC Fan #8"}, {IR, 485, 0, "Operating Hours EC Fan #7"},
{IR, 488, 0, "Operating Hours EC Fan #9"}, {IR, 486, 0, "Operating Hours EC Fan #8"},
{COIL, 301, 0, "ON/OFF Command By BMS"}, {IR, 487, 0, "Operating Hours EC Fan #9"},
{COIL, 302, 0, "Enable Off By Supervisory"}, {COIL, 300, 0, "ON/OFF Command By BMS"},
{COIL, 301, 0, "Enable Off By Supervisory"},
{COIL, 264, 0, "Alarm Reset"} {COIL, 264, 0, "Alarm Reset"}
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.

View File

@@ -0,0 +1,51 @@
# Humidifier Dri-Steem RTS RX-36-1 TCP
## Brief Introduction
This humidifier receives on/off commands and RH Setpoint from the PLC.
The Space RH register is not used, since there will not be a Space RH sensor wired to the HUM unit.
The RH Setpoint will be determined based on dewpoints in the datahall. See QTS SOO for details.
## List of Equipment
This configuration has been used for these models:
* **RTS RX-36-1**: 10-28-2025
## Hardware Prerequisites
The code is written for an ESP8266/ESP32-style microcontroller with WiFi capabilities.
* **Microcontroller**: [Firebeetle 2 ESP32.](https://www.dfrobot.com/product-2231.html)
---
## States and Strategies
Provide a brief description of what variables and strategies were used in this configuraiton
### Standby State
Run Mode = 3 (system standby)
Duct RH = 35 +/- 5
Fill Valve, Drain Valve = 0
Steam Demand Mass/Pct = 0
Steam Output Mass/Pct = 0
If any alarms active or safety interlock = 0 --> FailState
Checks for Run Mode = 1 AND Air Proving Switch = 1 --> RunningState
### Running State
Run Mode = 1 (auto)
If any alarms active or safety interlock = 0 --> FailState
If Run Mode = 3 or loss of airflow --> StandbyState
Reads RH Setpoint from PLC
DuctRH will dynamically ramp to RH Setpoint
Fill Valve and Drain Valve switch between 0 and 1 (squareStrategy)
Steam Demand Mass between 3-6 (sawStrategy)
Steam Demand Percent between 50-80% (sawStrategy)
Tank Temp = 80 +/- 3
Steam Output Mass = 4 +/- 1
Steam Output Percent = 65 +/- 10
Water Until ADS/Service will ramp down to 0 (initializes at 1500 and 10000)
### Fail State
Run Mode = 3 (system standby)
Duct RH = 35 +/- 5
Fill Valve, Drain Valve = 0
Steam Demand Mass/Pct = 0
Steam Output Mass/Pct = 0
When all alarms are cleared and safety interlock = 1 --> StandbyState

View File

@@ -0,0 +1,91 @@
/**
* @file StateUtils.cpp
* @brief Implementation of the StateUtils class.
* @author Robert J. Davis
* @date 2025-10-28
*
* This file contains implementation of utility functions that are used in multiple States.
*/
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_Random.h"
#include "Strategies/Strategy_Saw.h"
#include "Strategies/Strategy_SingleValue.h"
#include "Strategies/Strategy_Square.h"
#include "Strategies/Strategy_PID.h"
#include "ModbusPoints/Modbus_Point.h"
#include "ModbusPoints/Modbus_FloatDecorator.h"
#include "Equipment/Equipment.h"
#include "States/State_Standby.h"
#include "States/State_Running.h"
#include "States/State_Fail.h"
#include "States/State.h"
#include "StateUtils.h"
#include <vector>
#include <string>
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
/**
* @brief This function will update the Alarm bits and Safety Interlock state (based on Safety Interlock ON coil - for testing only)
* If the "Clear All Active Alarms" coil is activate, all alarms will be cleared, the Safety Interlock will be set to 1 (ready to operate),
* and the "Manual Clear Alarm Exists" bit will be set to 1.
* The "Alarms Present" (DI 10) will be set to 1 if any alarm is active (or Safety Interlock = 0). This is a register used for
* testing only, and will be used in Standby and Running States to send to FailState.
*
* This function is used in the update() of the Standby, Running, and Fail States.
*
*/
void updateAlarms(Equipment<ModbusIP>* equipment){
const std::vector<std::string> alarmDescriptions = {
"Tank Temp Sensor Fail", "Tank Overtemp", "Input RH Out of Range", "Duct RH Out of Range",
"Water Probe Check", "Water Probe Faulty", "Fill Time Excessive", "Refill Time Excessive",
"Tank Not Draining", "Boil Time Excessive"
};
// update Safety Interlock state (note: Safety Interlock = 0 means the equipment cannot run- fail safe)
if (equipment->getModbus_Point("Safety Interlock ON")->getValue() == 1){
equipment->setModbus_Point("Safety Interlock", 0);
}
else equipment->setModbus_Point("Safety Interlock", 1);
// if "Clear All Active Alarms" bit is 1 --> clear all alarms as well as safety interlock
// if "Clear All Active Alarms" bit is 0 --> if any alarms present set "Alarms Present" register to 1
if (equipment->getModbus_Point("Clear All Active Alarms")->getValue() == 1){
for (int i =0; i < alarmDescriptions.size(); ++i) {
equipment->setModbus_Point(alarmDescriptions[i], 0);
}
equipment->setModbus_Point("Safety Interlock ON", 0);
equipment->setModbus_Point("Safety Interlock", 1);
equipment->setModbus_Point("Alarms Present", 0);
equipment->setModbus_Point("Manual Clear Alarm Exists", 1); // the only way to set this back to 0 is manually via Modscan
}
else {
int numAlarms = 0;
for (int i =0; i < alarmDescriptions.size(); ++i) {
Modbus_Point<ModbusIP>* alarmPoint = equipment->getModbus_Point(alarmDescriptions[i]);
if (alarmPoint->getValue() == 1) numAlarms++;
}
if (equipment->getModbus_Point("Safety Interlock")->getValue() == 0) numAlarms++;
if (numAlarms >= 1) equipment->setModbus_Point("Alarms Present", 1);
else equipment->setModbus_Point("Alarms Present", 0);
}
}
/**
* @brief This function is used to update the Airflow Proving Switch state (DI 1)
* based on the Safety Interlock ON coil (Coil 2) - this is used for testing purposes only.
*
* This function is used in the update() of the Standby, Running, and Fail States.
*
*/
void updateAirflow(Equipment<ModbusIP>* equipment){
if (equipment->getModbus_Point("Airflow ON")->getValue() == 1){
equipment->setModbus_Point("Airflow Proving Switch", 1);
}
else equipment->setModbus_Point("Airflow Proving Switch", 0);
}

View File

@@ -0,0 +1,43 @@
/**
* @file config.h
* @brief StateUtils class
* @author Robert J Davis
* @date 2025-10-28
*
* Defines the StateUtils class, which contains utility functions used in multiple States.
*/
#pragma once
#include "ModbusPoints/Modbus_Point.h"
#include "ModbusPoints/Modbus_FloatDecorator.h"
#include "Equipment/Equipment.h"
#include "States/State_Standby.h"
#include "States/State_Running.h"
#include "States/State_Fail.h"
#include "States/State.h"
#include <vector>
#include <string>
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
template <typename T>
class State;
/**
* @brief Updates all alarms, safety interlock, alarms present register.
* @param equipment Pointer to the Equipment instance.
* @return void
*/
void updateAlarms(Equipment<ModbusIP>* equipment);
/**
* @brief Updates the Airflow Proving Switch state based on Airflow ON state.
* @param equipment Pointer to the Equipment instance.
* @return void
*/
void updateAirflow(Equipment<ModbusIP>* equipment);

View File

@@ -0,0 +1,91 @@
/**
* @file State_Fail.cpp
* @brief Implementation of the FailState class.
* @author Robert J Davis
* @date 2025-10-28
*
* This file contains the implementation for the FailState, which defines
* the behavior of the equipment when it has entered a fault condition.
*/
#include "ModbusPoints/Modbus_Point.h"
#include "Equipment/Equipment.h"
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_SingleValue.h"
#include "Strategies/Strategy_PID.h"
#include "States/State_Standby.h"
#include "States/State_Running.h"
#include "States/State_Fail.h"
#include "StateUtils.h"
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
/**
* @brief Constructs a new FailState object with a list of active alarms.
*
* This constructor will have the Duct RH fluctuate around 35% (for visualization purposes).
*
* @param activeAlarms A vector of strings, where each string is the
* description of a Modbus point to be set as an active alarm.
* This parameter is not used in this implementation of the Fail State.
*/
template<>
FailState<ModbusIP>::FailState(const std::vector<std::string>& activeAlarms) {
addStrategy("Duct RH", new SingleValueStrategy(35.0f, 5.0f, 1000));
addStrategy("Tank Temp", new SingleValueStrategy(80.0f, 1.0f, 3000));
}
/**
* @brief Executes the fail state's logic for one update cycle.
*
* Update Alarms states. Stays in FailState until all alarms are cleared --> Standby State.
*
* @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr.
*/
template<>
State<ModbusIP>* FailState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
// STATE control, add conditions if change to a different state is needed
Serial.println("Fail update function");
updateAlarms(equipment);
bool alarmsPresent = getPointValue(equipment, "Alarms Present");
if (!alarmsPresent){
return new StandbyState<ModbusIP>();
}
_applyStrategies(equipment);
return nullptr;
}
/**
* @brief Logic to execute once when entering the fail state.
* Sets the Run Mode to 3 (system standby), and appropriate analogs to 0.
* @param equipment Pointer to the Equipment instance.
*/
template<>
void FailState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state
Serial.println("Enter Fail State...");
// Ensure Run Mode set to 3 (standby)
setPointValue(equipment, "Run Mode", 3);
setPointValue(equipment, "Fill Valve", 0);
setPointValue(equipment, "Drain Valve", 0);
setPointValue(equipment, "Steam Demand Mass", 0);
setPointValue(equipment, "Steam Demand Percent", 0);
setPointValue(equipment, "Steam Output Mass", 0);
setPointValue(equipment, "Steam Output Percent", 0);
}
/**
* @brief Logic to execute once when exiting the fail state.
* @param equipment Pointer to the Equipment instance.
*/
template<>
void FailState<ModbusIP>::exitState(Equipment<ModbusIP>* equipment) {
// Cleanup logic to run when the equipment leaves this state
Serial.println("Exit Fail State...");
}

View File

@@ -0,0 +1,123 @@
/**
* @file State_Running.cpp
* @brief Implementation of the RunningState class.
* @author Robert J Davis
* @date 2025-10-28
*
* This file contains the implementation for the RunningState, which defines
* the behavior of the equipment when it is actively running.
*/
#include "ModbusPoints/Modbus_Point.h"
#include "ModbusPoints/Modbus_FloatDecorator.h"
#include "Equipment/Equipment.h"
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_Random.h"
#include "Strategies/Strategy_Saw.h"
#include "Strategies/Strategy_SingleValue.h"
#include "Strategies/Strategy_Square.h"
#include "Strategies/Strategy_PID.h"
#include "Strategies/Strategy_Totalizer.h"
#include "States/State_Standby.h"
#include "States/State_Running.h"
#include "States/State_Fail.h"
#include "States/State.h"
#include "StateUtils.h"
#include <vector>
#include <string>
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
/**
* @brief Constructs a new RunningState object.
*
* This constructor initializes behavior strategies active during the running
* state including various analog values. Fill and Drain Valves switch between 0 and 1.
* Water Until ADS/Service will ramp down to 0, initialized at 1500 and 10000, respectively.
*/
template<>
RunningState<ModbusIP>::RunningState() {
addStrategy("Duct RH", new RampStrategy(40.0f, 1.0f, 2000));
addStrategy("Fill Valve", new SquareStrategy(1.0f, 0.0f, 5000));
addStrategy("Drain Valve", new SquareStrategy(0.0f, 1.0f, 4500));
addStrategy("Steam Demand Mass", new SawStrategy(3.0f, 6.0f, 1.0f, 2000)); // these values are semi-random for visualization
addStrategy("Steam Demand Percent", new SawStrategy(50.0f, 80.0f, 5.0f, 1000)); // these values are semi-random for visualization
addStrategy("Tank Temp", new SingleValueStrategy(80.0f, 3.0f, 1000)); // these values are semi-random for visualization
addStrategy("Steam Output Mass", new SingleValueStrategy(4.0f, 1.0f, 1000)); // these values are semi-random for visualization
addStrategy("Steam Output Percent", new SingleValueStrategy(65.0f, 10.0f, 1000)); // these values are semi-random for visualization
addStrategy("Water Until ADS", new RampStrategy(0.0f, 1.0f, 2000)); // ramping down to 0 from 1500
addStrategy("Water Until Service", new RampStrategy(0.0f, 1.0f, 2000)); // ramping down to 0 from 10000
}
/**
* @brief Executes the running state's logic for one update cycle.
*
* This method first checks if there are any active alarms --> FailState.
* Also updates Airflow state according to Airflow ON (Coil 1- for testing use only).
* If no alarms are active, checks for loss of airflow or "Run Mode" = 3 (Modscan, but will be from PLC)
* to transition to the Standby state. If no transition is triggered, it updates the
* rampStrategy targetValue of the Duct RH to dynamically ramp up to the Space RH Setpoint (sent from PLC).
*
* @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr.
*/
template<>
State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
// Update alarms states and airflow switch state
updateAlarms(equipment);
updateAirflow(equipment);
// if Alarms are present (as updated in updateAlarms function) --> FailState
bool alarmsPresent = getPointValue(equipment, "Alarms Present");
if (alarmsPresent){
std::vector<std::string> activeAlarmsDesc = {}; // sending a blank string to FailState, b/c that parameter not used in FailState implementation.
return new FailState<ModbusIP>(activeAlarmsDesc);
}
// Check for Run Mode and Airflow. If Run Mode = 3 OR Airflow stopped --> StandbyState
int runMode_Command = getPointValue(equipment, "Run Mode"); // Set by PLC
int airflow = getPointValue(equipment, "Airflow Proving Switch");
if (runMode_Command == 3 || airflow == 0) {
return new StandbyState<ModbusIP>();
}
// Set the Duct RH ramp target value equal to the Space RH Setpoint
float Space_RH_Setpoint = getPointValue(equipment, "Space RH Setpoint");
float ductRH = getPointValue(equipment, "Duct RH");
Strategy_Behavior* DuctRH_strat = getStrategy("Duct RH");
if (DuctRH_strat){
static_cast<RampStrategy*>(DuctRH_strat)->setTarget(Space_RH_Setpoint);
}
// Apply any strategies defined for the standby state
_applyStrategies(equipment);
return nullptr;
}
/**
* @brief Logic to execute once when entering the running state.
*
* Note: do not need to set Run Mode = 1 (auto) since that is required to
* send the unit to Run Mode in the first place. Run Mode will already = 1.
*
* @param equipment Pointer to the Equipment instance.
*/
template<>
void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state
Serial.println("Enter Running State...");
}
/**
* @brief Logic to execute once when exiting the running state.
* @param equipment Pointer to the Equipment instance.
*/
template<>
void RunningState<ModbusIP>::exitState(Equipment<ModbusIP>* equipment) {
// Cleanup logic to run when the equipment leaves this state
Serial.println("Exit Running State...");
}

View File

@@ -0,0 +1,110 @@
/**
* @file State_Standby.cpp
* @brief Implementation of the StandbyState class.
* @author Robert J Davis
* @date 2025-10-28
*
* This file contains the implementation for the StandbyState, which defines
* the behavior of the equipment when it is in an idle or standby mode.
*/
#include "ModbusPoints/Modbus_Point.h"
#include "ModbusPoints/Modbus_FloatDecorator.h"
#include "Equipment/Equipment.h"
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_Random.h"
#include "Strategies/Strategy_Saw.h"
#include "Strategies/Strategy_SingleValue.h"
#include "Strategies/Strategy_Square.h"
#include "Strategies/Strategy_PID.h"
#include "States/State_Standby.h"
#include "States/State_Running.h"
#include "States/State_Fail.h"
#include "States/State.h"
#include "StateUtils.h"
#include <vector>
#include <string>
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
/**
* @brief Constructs a new StandbyState object.
*
* In this state, the equipment is idle. This constructor will have
* Duct RH fluctuate around 35% for visualization purposes only.
*
*/
template<>
StandbyState<ModbusIP>::StandbyState() {
addStrategy("Duct RH", new SingleValueStrategy(35.0f, 5.0f, 1000));
addStrategy("Tank Temp", new SingleValueStrategy(80.0f, 1.0f, 3000));
}
/**
* @brief Executes the standby state's logic for one update cycle.
*
* This method first checks for state transition commands:
* 1. Updates Alarm states
* 2. Updates Airflow Switch state (based on Airflow ON command - used just for simulation purposes)
* If any Alarms are active or Safety Interlock = 0, send to FailState.
*
* 3. Check if Run Mode = 1 and Airflow Switch = 1, then send to Running State.
*
* If no transition occurs, it applies the strategies defined for the standby state.
*
* @return A pointer to a new State if a transition should occur, otherwise nullptr.
*/
template<>
State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
// STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function");
updateAlarms(equipment);
updateAirflow(equipment);
// if Alarms are present (as updated in updateAlarms function) --> FailState
bool alarmsPresent = getPointValue(equipment, "Alarms Present");
if (alarmsPresent){
std::vector<std::string> activeAlarmsDesc = {}; // sending a blank string to FailState, b/c that parameter not used in FailState implementation.
return new FailState<ModbusIP>(activeAlarmsDesc);
}
// Check for Run Mode and Airflow Proving Switch. If Run Mode = 1 and there is Airflow --> RunningState
int runMode_Command = getPointValue(equipment, "Run Mode"); // Set by PLC
int airflow = getPointValue(equipment, "Airflow Proving Switch");
if (airflow == 1 && runMode_Command == 1) {
return new RunningState<ModbusIP>();
}
// Apply any strategies defined for the standby state
_applyStrategies(equipment);
return nullptr;
}
/**
* @brief Logic to execute once when entering the standby state.
* @param equipment Pointer to the Equipment instance.
*/
template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
Serial.println("Enter Standby State...");
// Set Run Mode to 3 (standby), just in case entered Standby on loss of airflow
setPointValue(equipment, "Run Mode", 3);
setPointValue(equipment, "Fill Valve", 0);
setPointValue(equipment, "Drain Valve", 0);
setPointValue(equipment, "Steam Demand Mass", 0);
setPointValue(equipment, "Steam Demand Percent", 0);
setPointValue(equipment, "Steam Output Mass", 0);
setPointValue(equipment, "Steam Output Percent", 0);
}
/**
* @brief Logic to execute once when exiting the standby state.
* @param equipment Pointer to the Equipment instance.
*/
template<>
void StandbyState<ModbusIP>::exitState(Equipment<ModbusIP>* equipment) {
// Cleanup logic to run when the equipment leaves this state
Serial.println("Exit Standby State...");
}

View File

@@ -0,0 +1,108 @@
/**
* @file config.h
* @brief Main configuration file for the DriSteem Humidifier (TCP) emulator.
* @author Robert J Davis
* @date 2025-10-27
*
* This file contains two important configurations: WiFi network parameters
* and the Modbus register map for the device.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "core.h"
#include "Equipment/Equipment.h"
#if defined(USE_MODBUS_IP)
/**
* @defgroup ModbusTCPConfig Modbus IP Configuration
* @brief Parameters for Modbus TCP communication.
* @{
*/
#include <ModbusIP_ESP8266.h>
const char *ssid = "TP-Link_D91A"; /**< @brief The SSID of the WiFi network. */
const char *password = "52761492"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(192, 168, 1, 234); /**< @brief The static IP address for the device. */
IPAddress gateway(192, 168, 1, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb;
#else
/**
* @defgroup ModbusRTUConfig Modbus RTU Configuration
* @brief Parameters for serial Modbus RTU communication.
* @{
*/
#include <ModbusRTU.h>
const int BAUDRATE = 19200; /**< @brief The serial communication speed in bits per second. */
const int RX_PIN = 17; /**< @brief The GPIO pin used for receiving data (RX). */
const int TX_PIN = 16; /**< @brief The GPIO pin used for transmitting data (TX). */
const int RST_PIN = 4; /**< @brief The GPIO pin connected to the RS485 driver's DE/RE pins for direction control. */
const int MODBUS_ID = 1; /**< @brief The unique slave ID for this device on the Modbus bus. */
/** @} */
/** @brief Global instance of the Modbus RTU server. */
ModbusRTU mb;
#endif
/**
* @defgroup ModbusMapConfig Modbus Map Configuration
* @brief Defines the Modbus register map and related parameters for the emulator.
* @{
*/
/**
* @brief The Modbus map for the Equipment device.
* This array defines all the Modbus points available on the emulated device.
* The `description` field is crucial as it's used to look up points within the application logic.
*/
modbusMap mb_map[] =
{
{COIL, 0, 0, "Airflow ON"}, // Used for Modscan testing only to set Airflow Proving Switch
{COIL, 1, 0, "Safety Interlock ON"}, // Used for Modscan testing only to trip Safety Interlock
{COIL, 2, 0, "Manual Clear Alarm Exists"},
{COIL, 3, 0, "Clear All Active Alarms"}, // OCmd_Reset
{COIL, 4, 0, "Tank Temp Sensor Fail"},
{COIL, 5, 0, "Tank Overtemp"},
{COIL, 6, 0, "Input RH Out of Range"},
{COIL, 7, 0, "Duct RH Out of Range"},
{COIL, 9, 0, "Water Probe Check"},
{COIL, 10, 0, "Water Probe Faulty"},
{COIL, 11, 0, "Fill Time Excessive"},
{COIL, 12, 0, "Refill Time Excessive"},
{COIL, 13, 0, "Tank Not Draining"},
{COIL, 14, 0, "Boil Time Excessive"},
{DI, 0, 0, "Airflow Proving Switch"}, // 0:open, 1:closed
{DI, 2, 1, "Safety Interlock"}, // 0:open, 1:closed
{DI, 7, 0, "Fill Valve"}, // 0:closed, 1:open
{DI, 8, 0, "Drain Valve"}, // 0:not draining, 1:draining
{DI, 9, 0, "Alarms Present"}, // Used for Modscan testing only - not part of vendor Modbus table
{IR, 0, 0, "Space RH"}, // Relative_Humidity --> NOT USED, sensor not connected to HUM
{IR, 2, 0, "Duct RH"}, // OSet_CV
{IR, 3, 0, "Steam Demand Mass"},
{IR, 4, 0, "Steam Demand Percent"},
{IR, 6, 0, "Tank Temp"},
{IR, 7, 0, "Steam Output Mass"},
{IR, 8, 0, "Steam Output Percent"},
{IR_10x, 9, 1500, "Water Until ADS"}, // 1 = 100 lbs (I know this is 10x function only)
{IR_10x, 10, 10000, "Water Until Service"}, // 1 = 100 lbs (I know this is 10x function only)
{HR, 0, 3, "Run Mode"}, // Operation_Mode, 1:auto, 2:local standby, 3:system standby, 4:manual drain
{HR, 1, 0, "Space RH Setpoint"}, // Relative_Humidity_SP
{HR, 3, 85, "Duct High Limit Setpoint"},
};
//Size of modbus map used in FOR cycles, automatically calculated.
/**
* @brief The total number of entries in the `mb_map` array.
* This is calculated at compile time and used for iterating over the map.
*/
const int map_size = sizeof(mb_map) / sizeof(mb_map[0]);
/** @brief The main loop update interval in milliseconds. */
int interval = 250;
/** @} */ // End of ModbusMapConfig group
#endif // CONFIG_H

View File

@@ -0,0 +1,86 @@
/**
* @file main.cpp
* @brief Main execution program for the DriSteem Humidifier (TCP) Emulator.
* @author Emmanuel Hernandez Cruz, Robert J Davis
* @date 2025-09-02
*
* @details This file contains the main execution program for an Arduino-based emulator of the DriSteem Humidifier unit.
* The program uses a Wi-Fi connection to communicate via the Modbus IP protocol.
*
* The setup() function initializes the following:
* - Serial communication for debugging.
* - Wi-Fi connection using credentials from config.h.
* - A Modbus TCP server.
* - Modbus points (Coils, Holding Registers, etc.) based on a predefined map in config.h.
*
* The loop() function continuously:
* - Services the Modbus TCP server to handle incoming requests.
* - Periodically calls the main update loop for the emulated equipment, which
* manages state transitions and behavior strategies.
*
* @see config.h for Wi-Fi and Modbus configuration.
* @see Equipment.h for the main equipment logic.
* @see State.h for different equipment states.
* @see Strategies/Strategy_Behavior.h for value generation strategies.
* @see Modbus_Point.h for the base class for all Modbus points.
*/
//=================================================================================================================================
//Libraries and declaration of variables.
#include <WiFi.h>
#include "config.h"
#include "ModbusPoints/Modbus_PointFactory.h"
#if defined(USE_MODBUS_IP)
#include <ModbusIP_ESP8266.h>
#else
#include <ModbusRTU.h>
#endif
//=================================================================================================================================
/**
* @brief Initializes the application.
* @details This function runs once at startup. It configures the serial communication,
* Wi-Fi, and the Modbus server. It also creates and initializes all the Modbus points
* based on the `mb_map` array in `config.h`.
*/
void setup() {
Serial.begin(115200); //Serial comm start
WiFi.config(local_IP, gateway, subnet); // Wifi service start
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("Connected!!");
mb.server(); //Modbus server start
Serial.println("Server Created");
Serial.println(map_size);
for(int i = 0; i < map_size; i++){
Modbus_Point<ModbusIP>* point = createModbus_Point(&mb, mb_map[i].category, mb_map[i].address, mb_map[i].value, mb_map[i].description);
if (point) {
point->addToModbusServer();
EquipmentInstance.addModbus_Point(mb_map[i].description, point);
}
}
Serial.println("All modbus Points created");
Serial.println("Setup function ended");
}
//=================================================================================================================================
/**
* @brief The main application loop.
* @details This function runs repeatedly after setup() has completed. It performs two main actions:
* 1. It continuously services the Modbus server by calling `mb.task()` to handle
* incoming requests from a Modbus master.
* 2. At a fixed interval (defined in `config.h`), it calls `EquipmentInstance.update()`
* to run the emulator's internal state machine and behavior logic.
*/
void loop() {
mb.task();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
unsigned long startTime = millis();
EquipmentInstance.update();
unsigned long endTime = millis();
unsigned long elapsedTime = endTime - startTime;
Serial.printf("Control Execution time: %d ms\n", elapsedTime);
}
}

View File

@@ -1,13 +1,12 @@
# VFD ABB ACH580 RTU # VFD ABB ACH580 RTU
## Brief Introduction ## Brief Introduction
This is based on a 50hp motor, 480V, 65 FLA, 60Hz, 1800 rpm (PHX3 DC1/2) This is based on a 50hp motor, 480V, 65 FLA, 60Hz, 1800 rpm (PHX3 DC1/2).
Modbus addresses are based on 32-bit registers.
## List of Equipment ## List of Equipment
This configuration has been used for these models: This configuration has been used for these models:
* **ACH580**: 10-23-2025 * **ACH580**: 10-23-2025 (PHX3)
* **Model**: 09-15-23
* **Model**: 09-15-25
## Hardware Prerequisites ## Hardware Prerequisites
@@ -19,12 +18,11 @@ The code is written for an ESP8266/ESP32-style microcontroller with WiFi capabil
--- ---
## States and Strategies ## States and Strategies
The hardwire IO signals to/from VFD/PLC are Start Cmd, Stop Cmd, Speed Command, Speed Feedback, VFD Run Status, VFD Fault. The hardwire IO signals to/from VFD/PLC are Start Cmd, Stop Cmd, Speed Command, Speed Feedback, Run Status, Fault Status.
User needs to set the speed command (HR 150) in RPM from the PLC User needs to set the speed command (HR 150) in RPM from the PLC
User needs to set the Start command (HR 151) from the PLC User needs to set the Start command (HR 151) from the PLC
It appears these registers were arbitrarily chosen for the purpose of this Arduino simulation. It appears these hard IO registers were arbitrarily chosen for the purpose of this Arduino simulation.
The registers selected are based on FS Config file from CDR project. The registers selected are based on FS Config file from CDR project. Run Status and Fault Status registers were added for simulation.
Currently there is no connection on Speed Feedback, Run Status, or Fault from Arduino to PICS
### Standby State ### Standby State
* **Equipment**: Equipment parameters go back to 0 * **Equipment**: Equipment parameters go back to 0
@@ -37,4 +35,6 @@ Currently there is no connection on Speed Feedback, Run Status, or Fault from Ar
* **Totalizers Strategy**: Inverter kWh cnt, Hours Run * **Totalizers Strategy**: Inverter kWh cnt, Hours Run
### Fail State ### Fail State
* Not used * Enters Fail State if Fault Status is set to 0.
While in Fail State, the Start/Stop command is reset to 0.
The only way to exit Fail State is if Fault Status = 1 --> Standby State.

View File

@@ -1,16 +1,18 @@
/** /**
* @file State_Fail.cpp * @file State_Fail.cpp
* @brief Implementation of the FailState class. * @brief Implementation of the FailState class.
* @author Emmanuel Hernandez Cruz * @author Robert J Davis
* @date 2025-09-05 * @date 2025-10-30
* *
* This file contains the implementation for the FailState, which defines * This file contains the implementation for the FailState, which defines
* the behavior of the equipment when it has entered a fault condition. * the behavior of the equipment when it has entered a fault condition.
*
*/ */
#include "States/State_Standby.h" #include "States/State_Standby.h"
#include "States/State_Fail.h" #include "States/State_Fail.h"
#include "ModbusPoints/Modbus_Point.h" #include "ModbusPoints/Modbus_Point.h"
#include "Equipment/Equipment.h" #include "Equipment/Equipment.h"
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_SingleValue.h" #include "Strategies/Strategy_SingleValue.h"
#include "Strategies/Strategy_PID.h" #include "Strategies/Strategy_PID.h"
@@ -26,21 +28,28 @@
/** /**
* @brief Constructs a new FailState object. * @brief Constructs a new FailState object.
* *
* This constructor receives a list of alarm descriptions and creates strategies * This constructor sets the associated analog signals to the same values as Standby.
* to set the corresponding Modbus points to a value of 1, indicating an
* active alarm. It also initializes a PID strategy for the valve position.
*/ */
template<> template<>
FailState<ModbusRTU>::FailState(const std::vector<std::string>& activeAlarms) { FailState<ModbusRTU>::FailState(const std::vector<std::string>& activeAlarms) {
// Simulate a failure: set common alarm and a specific fan alarm. addStrategy("Motor Speed Used", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Speed Feedback", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Motor Speed estimated", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Motor Current", new RampStrategy(0.0f, 20.0f, 1000 ));
addStrategy("Motor Torque", new RampStrategy(0.0f, 20.0f, 1000 ));
addStrategy("Inverter Temperature", new RampStrategy(0.0f, 1.0f, 1000 ));
addStrategy("Output Frequency", new SingleValueStrategy(0.1f, 0.2f, 1000 ));
addStrategy("Output Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("DC Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("Output Power", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
} }
/** /**
* @brief Executes the fail state's logic for one update cycle. * @brief Executes the fail state's logic for one update cycle.
* *
* This method checks the "Clear Alm" Modbus point for a command to transition * While in FailState, the Unit cannot be started and the Start/Stop command is reset to 0.
* back to Standby, which would typically happen after a fault is cleared by a * When the fault is cleared --> Standby State.
* user. If no transition is requested, it continues to apply the failure strategies.
* *
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr. * @return A pointer to a new State if a transition should occur, otherwise nullptr.
@@ -49,24 +58,30 @@ template<>
State<ModbusRTU>* FailState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) { State<ModbusRTU>* FailState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) {
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Fail update function"); Serial.println("Fail update function");
int faultNotPresent = getPointValue(equipment, "Fault Status");
if(faultNotPresent == 1){
return new StandbyState<ModbusRTU>();
}
setPointValue(equipment, "Start/Stop", 0);
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
/** /**
* @brief Logic to execute once when entering the fail state. Sets the main alarm bit. * @brief Logic to execute once when entering the fail state. Sets the Run Status to 0.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>
void FailState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) { void FailState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Fail State..."); Serial.println("Enter Fail State...");
setPointValue(equipment, "Run Status", 0);
} }
/** /**
* @brief Logic to execute once when exiting the fail state. Clears the main alarm bit. * @brief Logic to execute once when exiting the fail state.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>

View File

@@ -1,7 +1,7 @@
/** /**
* @file State_Running.cpp * @file State_Running.cpp
* @brief Implementation of the RunningState class. * @brief Implementation of the RunningState class.
* @author Emmanuel Hernandez Cruz, Robert J Davis * @author Robert J Davis
* @date 2025-10-22 * @date 2025-10-22
* *
* This file contains the implementation for the RunningState, which defines * This file contains the implementation for the RunningState, which defines
@@ -36,12 +36,13 @@
* @brief Constructs a new RunningState object. * @brief Constructs a new RunningState object.
* *
* This constructor initializes behavior strategies active during the running * This constructor initializes behavior strategies active during the running
* state, such as a PID controller for the 'CW Valve Position' and totalizers * state, such as speed feedback, current, torque, hours run, etc.
* for the run-hours of each EC fan. * These values are based on a 50hp motor, 480V, 65 FLA, 60Hz, 1800 rpm (PHX3 DC1/2)
*/ */
template<> template<>
RunningState<ModbusRTU>::RunningState() { RunningState<ModbusRTU>::RunningState() {
addStrategy("Motor Speed Used", new RampStrategy(1800.0f, 100.0f, 1000)); addStrategy("Motor Speed Used", new RampStrategy(1800.0f, 100.0f, 1000));
addStrategy("Speed Feedback", new RampStrategy(1800.0f, 100.0f, 1000));
addStrategy("Motor Speed estimated", new RampStrategy(1800.0f, 100.0f, 1000)); addStrategy("Motor Speed estimated", new RampStrategy(1800.0f, 100.0f, 1000));
addStrategy("Motor Current", new RampStrategy(65.0f, 7.0f, 1000)); addStrategy("Motor Current", new RampStrategy(65.0f, 7.0f, 1000));
addStrategy("Motor Torque", new RampStrategy(90.0f, 10.0f, 1000)); addStrategy("Motor Torque", new RampStrategy(90.0f, 10.0f, 1000));
@@ -53,18 +54,16 @@ RunningState<ModbusRTU>::RunningState() {
addStrategy("Output Power", new RampStrategy(36.7f, 2.0f, 1000 )); addStrategy("Output Power", new RampStrategy(36.7f, 2.0f, 1000 ));
addStrategy("Inverter kWh cnt", new TotalizerStrategy(1000)); addStrategy("Inverter kWh cnt", new TotalizerStrategy(1000));
addStrategy("Hours Run", new TotalizerStrategy(1000)); addStrategy("Hours Run", new TotalizerStrategy(1000));
} }
/** /**
* @brief Executes the running state's logic for one update cycle. * @brief Executes the running state's logic for one update cycle.
* *
* This method first checks for state transition commands: * This method first checks for state transition commands:
* 1. It reads the "ON/OFF Command By BMS" point. If it's 0, it transitions to StandbyState. * 1. If Fault is 0 (there is a fault present) --> FailState
* 2. It reads the "Fault Code" point. If it's non-zero, it transitions to FailState, * 2. It reads the "Stop/Start" command point (from PLC). If it's 0, it transitions to StandbyState.
* passing the corresponding alarm description.
* *
* If no transition occurs, it applies the strategies defined for the running state. * If no transition occurs, it updates values according to speed setpoint sent from PLC.
* *
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr. * @return A pointer to a new State if a transition should occur, otherwise nullptr.
@@ -74,6 +73,17 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Running update function"); Serial.println("Running update function");
// If Fault Status = 0, there is a fault --> FailState
int faultNotPresent = getPointValue(equipment, "Fault Status");
if(faultNotPresent == 0){
return new FailState<ModbusRTU>({"Fault Status"});
}
int VFD_Start_Stop = getPointValue(equipment, "Start/Stop");
if (VFD_Start_Stop == 0){
return new StandbyState<ModbusRTU>();
}
float speed_pct = getPointValue(equipment, "Speed Cmd") / 1800.0f; float speed_pct = getPointValue(equipment, "Speed Cmd") / 1800.0f;
// Based on Affinity Laws. Motor: 65 FLA, 480V, 60Hz, 1800 rpm, 50hp // Based on Affinity Laws. Motor: 65 FLA, 480V, 60Hz, 1800 rpm, 50hp
float voltage_update = speed_pct * 480; float voltage_update = speed_pct * 480;
@@ -83,11 +93,6 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
float freq_update = speed_pct * 60; float freq_update = speed_pct * 60;
float power_update = speed_pct * speed_pct * speed_pct * 36.77f; // 50 hp ~ 36.77kW float power_update = speed_pct * speed_pct * speed_pct * 36.77f; // 50 hp ~ 36.77kW
int VFD_Start_Stop = getPointValue(equipment, "Start/Stop");
if (VFD_Start_Stop == 0){
return new StandbyState<ModbusRTU>();
}
float currentSP = getPointValue(equipment, "Speed Cmd"); float currentSP = getPointValue(equipment, "Speed Cmd");
Strategy_Behavior* motorSpeedUsed = getStrategy("Motor Speed Used"); Strategy_Behavior* motorSpeedUsed = getStrategy("Motor Speed Used");
// 2. Check if the strategy exists // 2. Check if the strategy exists
@@ -96,6 +101,11 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
static_cast<RampStrategy*>(motorSpeedUsed)->setTarget(currentSP); static_cast<RampStrategy*>(motorSpeedUsed)->setTarget(currentSP);
} }
Strategy_Behavior* speedFeedback = getStrategy("Speed Feedback");
if (speedFeedback) {
static_cast<RampStrategy*>(speedFeedback)->setTarget(currentSP);
}
// To have Motor Speed estimated slightly different - for purposes of differentiating in Ignition // To have Motor Speed estimated slightly different - for purposes of differentiating in Ignition
float rpm_est = currentSP * 0.98f; float rpm_est = currentSP * 0.98f;
Strategy_Behavior* motorSpeedEst = getStrategy("Motor Speed estimated"); Strategy_Behavior* motorSpeedEst = getStrategy("Motor Speed estimated");
@@ -140,19 +150,19 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
/** /**
* @brief Logic to execute once when entering the running state. * @brief Logic to execute once when entering the running state.
* Sets the "Chiller Sts" point to indicate the unit is running. * Sets the Run Status" point to indicate the unit is running.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>
void RunningState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) { void RunningState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
setPointValue(equipment, "Run Status", 1);
} }
/** /**
* @brief Logic to execute once when exiting the running state. * @brief Logic to execute once when exiting the running state.
* Sets the "Chiller Sts" point to indicate the unit is no longer running. * Sets the "Output Frequency" to 0.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>

View File

@@ -1,7 +1,7 @@
/** /**
* @file State_Standby.cpp * @file State_Standby.cpp
* @brief Implementation of the StandbyState class. * @brief Implementation of the StandbyState class.
* @author Emmanuel Hernandez Cruz, Robert J Davis * @author Robert J Davis
* @date 2025-10-23 * @date 2025-10-23
* *
* This file contains the implementation for the StandbyState, which defines * This file contains the implementation for the StandbyState, which defines
@@ -26,30 +26,31 @@
* @brief Constructs a new StandbyState object. * @brief Constructs a new StandbyState object.
* *
* In this state, the equipment is idle. This constructor initializes several * In this state, the equipment is idle. This constructor initializes several
* strategies to generate random values for various status points, simulating * strategies to simulate a live but non-operational unit. Most values are ramped down to 0.
* a live but non-operational unit.
*/ */
template<> template<>
StandbyState<ModbusRTU>::StandbyState() { StandbyState<ModbusRTU>::StandbyState() {
addStrategy("Output Frequency", new SingleValueStrategy(0.1f, 0.2f, 1000 ));
addStrategy("Output Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("DC Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("Output Power", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("Motor Speed Used", new RampStrategy(0.0f, 200.0f, 1000 )); addStrategy("Motor Speed Used", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Speed Feedback", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Motor Speed estimated", new RampStrategy(0.0f, 200.0f, 1000 )); addStrategy("Motor Speed estimated", new RampStrategy(0.0f, 200.0f, 1000 ));
addStrategy("Motor Current", new RampStrategy(0.0f, 20.0f, 1000 )); addStrategy("Motor Current", new RampStrategy(0.0f, 20.0f, 1000 ));
addStrategy("Motor Torque", new RampStrategy(0.0f, 20.0f, 1000 )); addStrategy("Motor Torque", new RampStrategy(0.0f, 20.0f, 1000 ));
addStrategy("Inverter Temperature", new RampStrategy(0.0f, 1.0f, 1000 )); addStrategy("Inverter Temperature", new RampStrategy(0.0f, 1.0f, 1000 ));
addStrategy("Output Frequency", new SingleValueStrategy(0.1f, 0.2f, 1000 ));
addStrategy("Output Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("DC Voltage", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
addStrategy("Output Power", new SingleValueStrategy(0.1f, 0.1f, 1000 ));
} }
/** /**
* @brief Executes the standby state's logic for one update cycle. * @brief Executes the standby state's logic for one update cycle.
* *
* This method checks the "Chiller On-Off" Modbus point for a command to * This method first checks for state transition commands:
* transition to the Running state. If no transition is requested, it applies * 1. If Fault is 0 (there is a fault present) --> FailState
* the strategies defined for the standby state. * 2. It reads the "Start/Stop" point (from PLC). If it's 1 --> RunningState
*
* If no transition is requested, it applies the strategies defined for the standby state.
* *
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr. * @return A pointer to a new State if a transition should occur, otherwise nullptr.
@@ -58,6 +59,13 @@ template<>
State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) { State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipment) {
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function"); Serial.println("Standby update function");
// If Fault Status = 0, there is a fault --> FailState
int faultNotPresent = getPointValue(equipment, "Fault Status");
if(faultNotPresent == 0){
return new FailState<ModbusRTU>({"Fault Status"});
}
int VFD_Start_Stop = getPointValue(equipment, "Start/Stop"); int VFD_Start_Stop = getPointValue(equipment, "Start/Stop");
if (VFD_Start_Stop == 1){ if (VFD_Start_Stop == 1){
return new RunningState<ModbusRTU>(); return new RunningState<ModbusRTU>();
@@ -69,14 +77,14 @@ State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
/** /**
* @brief Logic to execute once when entering the standby state. * @brief Logic to execute once when entering the standby state.
* Sets the "Chiller Sts" point to indicate the unit is not running. * Sets the "Run Status" point to indicate the unit is not running.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>
void StandbyState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) { void StandbyState<ModbusRTU>::enterState(Equipment<ModbusRTU>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "Run Status", 0);
} }
/** /**

View File

@@ -1,11 +1,13 @@
/** /**
* @file config.h * @file config.h
* @brief Main configuration file for the ABB ACH580 (VFD) emulator. * @brief Main configuration file for the ABB ACH580 VFD (RTU) emulator.
* @author Emmanuel Hernandez Cruz, Robert J Davis * @author Robert J Davis
* @date 2025-10-22 * @date 2025-10-22
* *
* This file contains important configurations for the Modbus RTU communication * This file contains important configurations for the Modbus RTU communication
* and the specific register map for the emulated device. * and the specific register map for the emulated device.
* These are 32-bit modbus registers.
* Added "Run Status" and "Fault Status" to simulated hard IO points and send feedback to PLC during simulation.
*/ */
#ifndef CONFIG_H #ifndef CONFIG_H
@@ -54,36 +56,32 @@
*/ */
modbusMap mb_map[] = modbusMap mb_map[] =
{ {
{HR, 149, 0, "Speed Cmd"}, // expecting rpm (1800 rpm max) {HR, 149, 1800, "Speed Cmd"}, // arbitrary register number - receive signal from PLC (hardwire IO in field); expecting rpm (1800 rpm max)
{HR, 151, 0, "Start/Stop"}, {HR, 151, 0, "Start/Stop"}, // arbitrary register number - receive signal from PLC (hardwire IO in practice)
{HR, 152, 0, "HOA Command"}, {HR, 152, 0, "HOA Command"}, // arbitrary register number - not used in program
{HR, 100, 0, "Motor Speed Used"}, // RJD: 1800 rpm max {HR, 154, 0, "Run Status"}, // arbitrary register number - 0:off, 1:on (simulated hardwire IO) sending feedback to PLC during simulation.
{HR, 101, 0, "Motor Speed estimated"}, // RJD: 1800 rpm max {HR, 155, 1, "Fault Status"}, // arbitrary register number - 0:faulted, 1:not faulted (simulated hardwire IO). When = 0, will turn off VFD.
{HR_10x, 105, 0, "Output Frequency"}, // 60 Hz @100% speed {HR, 156, 0, "Speed Feedback"}, // arbitrary register number - send signal to PLC (simulated hardwire IO). Will be equal to Motor Speed Used register
{HR, 106, 0, "Motor Current"}, // RJD: Changed from HR_10x to HR, 65 FLA
{HR_10x, 109, 0, "Motor Torque"}, // % of nominal torque
{HR_10x, 110, 0, "DC Voltage"}, // approx 678 VDC @100% speed
{HR, 112, 0, "Output Voltage"}, // RJD: 480 VAC
{HR, 113, 0, "Output Power"}, //max 372580 // RJD: Changed from HR_10x to HR, 50 hp ~ 36.77 kW
{HR_10x, 119, 0, "Inverter kWh cnt"},
{HR, 502, 0, "Hours Run"},
{HR, 510, 0, "Inverter Temperature"}, // RJD: Changed from HR_10x to HR, % of fault limit
{HR, 521, 0, "HOA Status Word"},
{HR, 410, 0, "Last Fault"}, {HR_FLOAT, 20201, 0, "Motor Speed Used"}, // RJD: 1800 rpm max
{HR, 411, 0, "2nd to last Fault"}, {HR_FLOAT, 20203, 0, "Motor Speed estimated"}, // RJD: 1800 rpm max
{HR, 412, 0, "3rd to last Fault"}, {HR_FLOAT, 20211, 0, "Output Frequency"}, // 60 Hz @100% speed
{HR, 439, 0, "Event Word Param"}, {HR_FLOAT, 20213, 0, "Motor Current"}, // RJD: Changed from HR_10x to HR, 65 FLA
{HR_FLOAT, 20219, 0, "Motor Torque"}, // % of nominal torque
{HR_FLOAT, 20221, 0, "DC Voltage"}, // approx 678 VDC @100% speed
{HR_FLOAT, 20225, 0, "Output Voltage"}, // RJD: 480 VAC
{HR_FLOAT, 20227, 0, "Output Power"}, //max 372580 // RJD: Changed from HR_10x to HR, 50 hp ~ 36.77 kW
{HR_FLOAT, 20239, 0, "Inverter kWh cnt"},
{HR_FLOAT, 21005, 0, "Hours Run"},
{HR_FLOAT, 21021, 0, "Inverter Temperature"}, // RJD: Changed from HR_10x to HR, % of fault limit
{HR, 610, 0, "Status Word 1"}, {HR, 21243, 0, "HOA Status Word"}, // not used in program
{HR, 615, 0, "Status Word 2"}, {HR, 20801, 0, "Trip Fault"}, // not used in program
{HR, 616, 0, "Status Word 3"}, {HR, 20821, 0, "Last Fault"}, // not used in program
{HR, 617, 0, "Status Word 4"}, {HR, 20823, 0, "2nd to last Fault"}, // not used in program
{HR, 618, 0, "Status Word 5"}, {HR, 20825, 0, "3rd to last Fault"}, // not used in program
{HR, 619, 0, "Status Word 6"}, {HR, 21221, 0, "Main Status Word"}, // not used in program
{HR, 620, 0, "Status Word 7"}, {HR, 21231, 0, "Drive Status Word 1"}, // not used in program
{HR, 621, 0, "Status Word 8"},
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.
/** /**

View File

@@ -1,11 +1,11 @@
/** /**
* @file main.cpp * @file main.cpp
* @brief Main execution program for the Daikin Chiller (RTU) Emulator. * @brief Main execution program for the ABB ACH580 VFD (RTU) Emulator.
* @author Emmanuel Hernandez Cruz * @author Emmanuel Hernandez Cruz, Robert J Davis
* @date 2025-09-02 * @date 2025-09-02
* *
* @details This file contains the main execution program for an Arduino-based * @details This file contains the main execution program for an Arduino-based
* emulator of a Daikin Chiller unit. The program communicates via the * emulator of a ABB ACH580 VFD unit. The program communicates via the
* Modbus RTU protocol over a serial connection. * Modbus RTU protocol over a serial connection.
* *
* The setup() function initializes the following: * The setup() function initializes the following:

View File

@@ -39,20 +39,19 @@
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("Source 1 Volts AB", new SingleValueStrategy(0.0F, 0.0f, 1000));
addStrategy("Source 1 Volts BC", new SingleValueStrategy(0.0F, 0.0f, 1000));
addStrategy("Source 2 Volts CA", new SingleValueStrategy(0.0F, 0.0f, 1000));
addStrategy("Source 2 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 2 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 2 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 2 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 2 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 2 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 1 Frequency", new SingleValueStrategy(0.0f, 0.0f, 1000));
addStrategy("Source 2 Frequency", new SingleValueStrategy(60.0f, 1.0f, 1000)); addStrategy("Source 2 Frequency", new SingleValueStrategy(60.0f, 1.0f, 1000));
addStrategy("Power Factor", new SingleValueStrategy(90.0f, 2.0f, 1000)); addStrategy("Power Factor", new SingleValueStrategy(90.0f, 2.0f, 1000));
addStrategy("Volts AB", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Amps A", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("Votls BC", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("Volts CA", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Amps C", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("Amps A", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Amps C", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Total Active Power", new SingleValueStrategy(6.0f, 5.0f, 1000));
addStrategy("Total Apparent Power", new SingleValueStrategy(6.0f, 5.0f, 1000));
} }
@@ -78,20 +77,40 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
int I_load = getPointValue(equipment, "ATS_Load"); float load = getPointValue(equipment, "ATS_Load");
int I_rating = getPointValue(equipment, "ATS_Rating"); float rating = getPointValue(equipment, "ATS_Rating");
float load = static_cast<float>(I_load); float sim_load = rating * (load/100.0f);
float rating = static_cast<float>(I_rating);
float real_load = rating * (load/100.0f);
Strategy_Behavior* ampsA_svs = getStrategy("Amps A"); Strategy_Behavior* ampsA_svs = getStrategy("Amps A");
Strategy_Behavior* ampsB_svs = getStrategy("Amps B"); Strategy_Behavior* ampsB_svs = getStrategy("Amps B");
Strategy_Behavior* ampsC_svs = getStrategy("Amps C"); Strategy_Behavior* ampsC_svs = getStrategy("Amps C");
static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(sim_load);
static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(sim_load);
static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(sim_load);
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
float v_ab = getPointValue(equipment, "Source 2 Volts AB");
float v_bc = getPointValue(equipment, "Source 2 Volts BC");
float v_ca = getPointValue(equipment, "Source 2 Volts CA");
float i_a = getPointValue(equipment, "Amps A");
float i_b = getPointValue(equipment, "Amps B");
float i_c = getPointValue(equipment, "Ampc C");
float pwr = ((v_ab * i_a) + (v_bc * i_b) + (v_ca * i_c));
setPointValue(equipment, "Total Active Power", pwr*1000.0f);
float pf = getPointValue(equipment, "Power Factor");
float a_pwr = pwr * (pf/100.0f);
setPointValue(equipment, "Total Apparent Power", a_pwr*1000.0f);
float preferred = getPointValue(equipment, "ATS_Preferred");
if (preferred == 1.0f){
setPointValue(equipment, "Source 1 Preferred", 1.0f);
setPointValue(equipment, "Source 2 Preferred", 0.0f);
}
if (preferred == 2.0f){
setPointValue(equipment, "Source 1 Preferred", 0.0f);
setPointValue(equipment, "Source 2 Preferred", 1.0f);
}
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
@@ -113,6 +132,11 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "Source 1 Preferred", 1); setPointValue(equipment, "Source 1 Preferred", 1);
setPointValue(equipment, "Source 2 Preferred", 0); setPointValue(equipment, "Source 2 Preferred", 0);
setPointValue(equipment, "Source 1 Volts AB", 0.0f);
setPointValue(equipment, "Source 1 Volts BC", 0.0f);
setPointValue(equipment, "Source 1 Volts CA", 0.0f);
setPointValue(equipment, "Source 1 Frequency", 0.0f);
int transferQty = getPointValue(equipment, "Number of Transfers"); int transferQty = getPointValue(equipment, "Number of Transfers");
setPointValue(equipment, "Number of Transfers", transferQty + 1); setPointValue(equipment, "Number of Transfers", transferQty + 1);
} }

View File

@@ -37,21 +37,21 @@
*/ */
template<> template<>
StandbyState<ModbusIP>::StandbyState() { StandbyState<ModbusIP>::StandbyState() {
// You can add initialization code here if needed // You can add initialization code here if needed
addStrategy("Source 1 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 1 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 1 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 1 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 1 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("Source 1 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000));
addStrategy("Source 2 Volts AB", new SingleValueStrategy(0.0F, 0.0f, 1000)); addStrategy("Source 1 Frequency", new SingleValueStrategy(60.0f, 1.0f, 1000));
addStrategy("Source 2 Volts BC", new SingleValueStrategy(0.0F, 0.0f, 1000)); addStrategy("Power Factor", new SingleValueStrategy(90.0f, 2.0f, 1000));
addStrategy("Source 2 Volts CA", new SingleValueStrategy(0.0F, 0.0f, 1000)); addStrategy("Volts AB", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Source 1 Frequency", new SingleValueStrategy(60.0f, 1.0f, 1000)); addStrategy("Votls BC", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Source 2 Frequency", new SingleValueStrategy(0.0f, 0.0f, 1000)); addStrategy("Volts CA", new SingleValueStrategy(480.0f, 2.0f, 1000));
addStrategy("Amps A", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Amps C", new SingleValueStrategy(1.0f, 3.0f, 1000));
addStrategy("Total Active Power", new SingleValueStrategy(6.0f, 5.0f, 1000));
addStrategy("Total Apparent Power", new SingleValueStrategy(6.0f, 5.0f, 1000));
addStrategy("Power Factor", new SingleValueStrategy(90.0f, 2.0f, 1000));
addStrategy("Amps A", new SingleValueStrategy(1.0f, 5.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 5.0f, 1000));
addStrategy("Amps C", new SingleValueStrategy(1.0f, 5.0f, 1000));
} }
/** /**
@@ -73,19 +73,42 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
return new RunningState<ModbusIP>(); return new RunningState<ModbusIP>();
} }
int I_load = getPointValue(equipment, "ATS_Load"); float load = getPointValue(equipment, "ATS_Load");
int I_rating = getPointValue(equipment, "ATS_Rating"); float rating = getPointValue(equipment, "ATS_Rating");
float load = static_cast<float>(I_load); float sim_load = rating * (load/100.0f);
float rating = static_cast<float>(I_rating);
float real_load = rating * (load/100.0f);
Strategy_Behavior* ampsA_svs = getStrategy("Amps A"); Strategy_Behavior* ampsA_svs = getStrategy("Amps A");
Strategy_Behavior* ampsB_svs = getStrategy("Amps B"); Strategy_Behavior* ampsB_svs = getStrategy("Amps B");
Strategy_Behavior* ampsC_svs = getStrategy("Amps C"); Strategy_Behavior* ampsC_svs = getStrategy("Amps C");
static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(sim_load);
static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(sim_load);
static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(sim_load);
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
float v_ab = getPointValue(equipment, "Source 1 Volts AB");
float v_bc = getPointValue(equipment, "Source 1 Volts BC");
float v_ca = getPointValue(equipment, "Source 1 Volts CA");
float i_a = getPointValue(equipment, "Amps A");
float i_b = getPointValue(equipment, "Amps B");
float i_c = getPointValue(equipment, "Ampc C");
float pwr = ((v_ab * i_a) + (v_bc * i_b) + (v_ca * i_c));
setPointValue(equipment, "Total Active Power", pwr*1000.0f);
float pf = getPointValue(equipment, "Power Factor");
float a_pwr = pwr * (pf/100.0f);
setPointValue(equipment, "Total Apparent Power", a_pwr*1000.0f);
/*setPointValue(equipment, "S2 kW", kw);
setPointValue(equipment, "S2 MWh", mwh);*/
float preferred = getPointValue(equipment, "ATS_Preferred");
if (preferred == 1.0f){
setPointValue(equipment, "Source 1 Preferred", 1.0f);
setPointValue(equipment, "Source 2 Preferred", 0.0f);
}
if (preferred == 2.0f){
setPointValue(equipment, "Source 1 Preferred", 0.0f);
setPointValue(equipment, "Source 2 Preferred", 1.0f);
}
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
@@ -107,6 +130,11 @@ void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "Source 1 Preferred", 0); setPointValue(equipment, "Source 1 Preferred", 0);
setPointValue(equipment, "Source 2 Preferred", 1); setPointValue(equipment, "Source 2 Preferred", 1);
setPointValue(equipment, "Source 2 Volts AB", 0.0f);
setPointValue(equipment, "Source 2 Volts BC", 0.0f);
setPointValue(equipment, "Source 2 Volts CA", 0.0f);
setPointValue(equipment, "Source 2 Frequency", 0.0f);
int transferQty = getPointValue(equipment, "Number of Transfers"); int transferQty = getPointValue(equipment, "Number of Transfers");
setPointValue(equipment, "Number of Transfers", transferQty + 1); setPointValue(equipment, "Number of Transfers", transferQty + 1);
} }

View File

@@ -21,10 +21,10 @@
* @{ * @{
*/ */
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "wifi_ssid"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "wifi_password"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(192, 168, 1, 15); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 172); /**< @brief The static IP address for the device. */
IPAddress gateway(192, 168, 1, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;
@@ -60,6 +60,7 @@
*/ */
modbusMap mb_map[] = modbusMap mb_map[] =
{ {
{HR, 8, 0, "ATS_Preferred"}, //Internal to control from Modscan
{HR, 9, 0, "ATS_Source"}, //Internal to control from Modscan {HR, 9, 0, "ATS_Source"}, //Internal to control from Modscan
{HR, 10, 0, "ATS_Load"}, //Internal Fault code from Modscan {HR, 10, 0, "ATS_Load"}, //Internal Fault code from Modscan
{HR, 11, 0, "ATS_Rating"}, //Internal Fault code from Modscan {HR, 11, 0, "ATS_Rating"}, //Internal Fault code from Modscan
@@ -86,9 +87,9 @@ modbusMap mb_map[] =
{IR, 6158, 0, "Amps A"}, {IR, 6158, 0, "Amps A"},
{IR, 6159, 0, "Amps B"}, {IR, 6159, 0, "Amps B"},
{IR, 6160, 0, "Amps C"}, {IR, 6160, 0, "Amps C"},
{IR_LONG, 6165, 0, "Total Active Power"}, {IR_LONG, 6165, 0, "Total Active Power"}, //0.001
{IR_LONG, 6169, 0, "Total Apparent Power"}, {IR_LONG, 6169, 0, "Total Apparent Power"}, //0.001
{IR, 6171, 0, "Power Factor"}, {IR, 6171, 0, "Power Factor"}, //0.001
{IR, 6263, 0, "Number of Transfers"}, {IR, 6263, 0, "Number of Transfers"},
{IR, 6297, 0, "Alarm Status Bits"}, {IR, 6297, 0, "Alarm Status Bits"},

View File

@@ -39,15 +39,15 @@
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("S2 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S2 Volts AB", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("S2 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S2 Volts BC", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("S2 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S2 Volts CA", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("PF", new SingleValueStrategy(90.0f, 2.0f, 1000)); addStrategy("PF", new SingleValueStrategy(910.0f, 20.0f, 1000));
addStrategy("S2 Amps A", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S2 Amps A", new SingleValueStrategy(200.0f, 100.0f, 1000));
addStrategy("S2 Amps B", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S2 Amps B", new SingleValueStrategy(200.0f, 100.0f, 1000));
addStrategy("S2 Amps C", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S2 Amps C", new SingleValueStrategy(200.0f, 100.0f, 1000));
} }
@@ -74,34 +74,47 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
} }
float volts_AB = getPointValue(equipment, "S2 Volts AB"); float volts_AB = getPointValue(equipment, "S2 Volts AB");
float volts_BC = getPointValue(equipment, "S2 Volts BC"); float volts_BC = getPointValue(equipment, "S2 Volts BC");
float volts_AC = getPointValue(equipment, "S2 Volts CA"); float volts_CA = getPointValue(equipment, "S2 Volts CA");
setPointValue(equipment, "S2 Volts AN", volts_AB/1.732); setPointValue(equipment, "S2 Volts AN", volts_AB/1.732);
setPointValue(equipment, "S2 Volts BN", volts_BC/1.732); setPointValue(equipment, "S2 Volts BN", volts_BC/1.732);
setPointValue(equipment, "S2 Volts CN", volts_AC/1.732); setPointValue(equipment, "S2 Volts CN", volts_CA/1.732);
int I_load = getPointValue(equipment, "ATS_Load"); int I_load = getPointValue(equipment, "ATS_Load");
int I_rating = getPointValue(equipment, "ATS_Rating"); int I_rating = getPointValue(equipment, "ATS_Rating");
float load = static_cast<float>(I_load); float load = static_cast<float>(I_load);
float rating = static_cast<float>(I_rating); float rating = static_cast<float>(I_rating);
float real_load = rating * (load/100.0f); float sim_load = rating * (load/100.0f);
Strategy_Behavior* ampsA_svs = getStrategy("S2 Amps A"); Strategy_Behavior* ampsA_svs = getStrategy("S2 Amps A");
Strategy_Behavior* ampsB_svs = getStrategy("S2 Amps B"); Strategy_Behavior* ampsB_svs = getStrategy("S2 Amps B");
Strategy_Behavior* ampsC_svs = getStrategy("S2 Amps C"); Strategy_Behavior* ampsC_svs = getStrategy("S2 Amps C");
static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(sim_load*1000.0f);
static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(sim_load*1000.0f);
static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(sim_load*1000.0f);
float pf = getPointValue(equipment, "PF"); float get_pf = getPointValue(equipment, "PF");
float pf = get_pf/1000.0f;
float real_v_AB = volts_AB/1000.0f;
float kw = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load * pf)/1000; float real_v_BC = volts_BC/1000.0f;
float kva = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load)/1000; float real_v_CA = volts_CA/1000.0f;
float kw = (1.732f * ((real_v_AB + real_v_BC + real_v_CA)/3.0f) * sim_load * pf)*10;
float mwh = kw *600.0f;
setPointValue(equipment, "S2 kW", kw); setPointValue(equipment, "S2 kW", kw);
setPointValue(equipment, "S2 kVA", kva); setPointValue(equipment, "S2 MWh", mwh);
float preferred = getPointValue(equipment, "ATS_Preferred");
if (preferred == 1.0f){
setBitValue(equipment, "Source Preferred", 9, true);
setBitValue(equipment, "Source Preferred", 8, false);
}
if (preferred == 2.0f){
setBitValue(equipment, "Source Preferred", 9, false);
setBitValue(equipment, "Source Preferred", 8, true);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
@@ -117,9 +130,6 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
setPointValue(equipment, "Source Active", 32);
setPointValue(equipment, "Source Preferred", 512);
setPointValue(equipment, "S1 Volts AB", 0.0f); setPointValue(equipment, "S1 Volts AB", 0.0f);
setPointValue(equipment, "S1 Volts BC", 0.0f); setPointValue(equipment, "S1 Volts BC", 0.0f);
setPointValue(equipment, "S1 Volts CA", 0.0f); setPointValue(equipment, "S1 Volts CA", 0.0f);
@@ -129,6 +139,14 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "S1 Amps A", 0.0f); setPointValue(equipment, "S1 Amps A", 0.0f);
setPointValue(equipment, "S1 Amps B", 0.0f); setPointValue(equipment, "S1 Amps B", 0.0f);
setPointValue(equipment, "S1 Amps C", 0.0f); setPointValue(equipment, "S1 Amps C", 0.0f);
setPointValue(equipment, "S1 kW", 0.0f);
setPointValue(equipment, "S1 MWh", 0.0f);
setBitValue(equipment, "Source Active", 4, false);
setBitValue(equipment, "Source Active", 3, true);
setBitValue(equipment, "Source Preferred", 8, false);
setBitValue(equipment, "Source Preferred", 9, true);
} }
/** /**

View File

@@ -38,15 +38,15 @@
template<> template<>
StandbyState<ModbusIP>::StandbyState() { StandbyState<ModbusIP>::StandbyState() {
// You can add initialization code here if needed // You can add initialization code here if needed
addStrategy("S1 Volts AB", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S1 Volts AB", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("S1 Volts BC", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S1 Volts BC", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("S1 Volts CA", new SingleValueStrategy(480.0F, 2.0f, 1000)); addStrategy("S1 Volts CA", new SingleValueStrategy(4800.0F, 10.0f, 1000));
addStrategy("PF", new SingleValueStrategy(90.0f, 2.0f, 1000)); addStrategy("PF", new SingleValueStrategy(910.0f, 20.0f, 1000));
addStrategy("S1 Amps A", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S1 Amps A", new SingleValueStrategy(200.0f, 100.0f, 1000));
addStrategy("S1 Amps B", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S1 Amps B", new SingleValueStrategy(200.0f, 100.0f, 1000));
addStrategy("S1 Amps C", new SingleValueStrategy(1.0f, 5.0f, 1000)); addStrategy("S1 Amps C", new SingleValueStrategy(200.0f, 100.0f, 1000));
} }
/** /**
@@ -68,33 +68,46 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
} }
float volts_AB = getPointValue(equipment, "S1 Volts AB"); float volts_AB = getPointValue(equipment, "S1 Volts AB");
float volts_BC = getPointValue(equipment, "S1 Volts BC"); float volts_BC = getPointValue(equipment, "S1 Volts BC");
float volts_AC = getPointValue(equipment, "S1 Volts CA"); float volts_CA = getPointValue(equipment, "S1 Volts CA");
setPointValue(equipment, "S1 Volts AN", volts_AB/1.732); setPointValue(equipment, "S1 Volts AN", volts_AB/1.732);
setPointValue(equipment, "S1 Volts BN", volts_BC/1.732); setPointValue(equipment, "S1 Volts BN", volts_BC/1.732);
setPointValue(equipment, "S1 Volts CN", volts_AC/1.732); setPointValue(equipment, "S1 Volts CN", volts_CA/1.732);
int I_load = getPointValue(equipment, "ATS_Load"); int I_load = getPointValue(equipment, "ATS_Load");
int I_rating = getPointValue(equipment, "ATS_Rating"); int I_rating = getPointValue(equipment, "ATS_Rating");
float load = static_cast<float>(I_load); float load = static_cast<float>(I_load);
float rating = static_cast<float>(I_rating); float rating = static_cast<float>(I_rating);
float real_load = rating * (load/100.0f); float sim_load = rating * (load/100.0f);
Strategy_Behavior* ampsA_svs = getStrategy("S1 Amps A"); Strategy_Behavior* ampsA_svs = getStrategy("S1 Amps A");
Strategy_Behavior* ampsB_svs = getStrategy("S1 Amps B"); Strategy_Behavior* ampsB_svs = getStrategy("S1 Amps B");
Strategy_Behavior* ampsC_svs = getStrategy("S1 Amps C"); Strategy_Behavior* ampsC_svs = getStrategy("S1 Amps C");
static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsA_svs)->setSetpoint(sim_load*1000.0f);
static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsB_svs)->setSetpoint(sim_load*1000.0f);
static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(real_load); static_cast<SingleValueStrategy*>(ampsC_svs)->setSetpoint(sim_load*1000.0f);
float pf = getPointValue(equipment, "PF"); float get_pf = getPointValue(equipment, "PF");
float pf = get_pf/1000.0f;
float real_v_AB = volts_AB/1000.0f;
float real_v_BC = volts_BC/1000.0f;
float real_v_CA = volts_CA/1000.0f;
float kw = (1.732f * ((real_v_AB + real_v_BC + real_v_CA)/3.0f) * sim_load * pf)*10;
float mwh = kw *600.0f;
float kw = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load * pf)/1000; float preferred = getPointValue(equipment, "ATS_Preferred");
float kva = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load)/1000; if (preferred == 1.0f){
setBitValue(equipment, "Source Preferred", 9, true);
setBitValue(equipment, "Source Preferred", 8, false);
}
if (preferred == 2.0f){
setBitValue(equipment, "Source Preferred", 9, false);
setBitValue(equipment, "Source Preferred", 8, true);
}
setPointValue(equipment, "S1 kW", kw); setPointValue(equipment, "S1 kW", kw);
setPointValue(equipment, "S1 kVA", kva); setPointValue(equipment, "S1 MWh", mwh);
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
@@ -109,8 +122,6 @@ template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "Source Active", 64);
setPointValue(equipment, "Source Preferred", 1024);
setPointValue(equipment, "S2 Volts AB", 0.0f); setPointValue(equipment, "S2 Volts AB", 0.0f);
setPointValue(equipment, "S2 Volts BC", 0.0f); setPointValue(equipment, "S2 Volts BC", 0.0f);
@@ -121,6 +132,14 @@ void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "S2 Amps A", 0.0f); setPointValue(equipment, "S2 Amps A", 0.0f);
setPointValue(equipment, "S2 Amps B", 0.0f); setPointValue(equipment, "S2 Amps B", 0.0f);
setPointValue(equipment, "S2 Amps C", 0.0f); setPointValue(equipment, "S2 Amps C", 0.0f);
setPointValue(equipment, "S2 kW", 0.0f);
setPointValue(equipment, "S2 MWh", 0.0f);
setBitValue(equipment, "Source Active", 3, false);
setBitValue(equipment, "Source Active", 4, true);
setBitValue(equipment, "Source Preferred", 8, false);
setBitValue(equipment, "Source Preferred", 9, true);
} }
/** /**

View File

@@ -23,7 +23,7 @@
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "123abc456"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(172, 17, 33, 241); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 173); /**< @brief The static IP address for the device. */
IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
@@ -60,35 +60,37 @@
*/ */
modbusMap mb_map[] = modbusMap mb_map[] =
{ {
{HR, 8, 0, "ATS_Preferred"}, //Internal to control from Modscan
{HR, 9, 0, "ATS_Source"}, //Internal to control from Modscan {HR, 9, 0, "ATS_Source"}, //Internal to control from Modscan
{HR, 10, 0, "ATS_Load"}, {HR, 10, 0, "ATS_Load"},
{HR, 11, 0, "ATS_Rating"}, //Internal Fault code from Modscan {HR, 11, 0, "ATS_Rating"}, //Internal Fault code from Modscan
{HR, 50009, 0, "PF"}, {HR, 50009, 0, "PF"}, //0.001x
{HR_LONG, 50001, 0, "S2 Volts AB"}, {HR_LONG, 50001, 0, "S2 Volts AB"}, //0.1x
{HR_LONG, 50004, 0, "S2 Volts AN"}, {HR_LONG, 50004, 0, "S2 Volts AN"}, //0.1x
{HR_LONG, 50007, 0, "S2 Volts BC"}, {HR_LONG, 50007, 0, "S2 Volts BC"}, //0.1x
{HR_LONG, 50010, 0, "S2 Volts BN"}, {HR_LONG, 50010, 0, "S2 Volts BN"}, //0.1x
{HR_LONG, 50013, 0, "S2 Volts CA"}, {HR_LONG, 50013, 0, "S2 Volts CA"}, //0.1x
{HR_LONG, 50016, 0, "S2 Volts CN"}, {HR_LONG, 50016, 0, "S2 Volts CN"}, //0.1x
{HR_LONG, 50019, 0, "S1 Volts AB"}, {HR_LONG, 50019, 0, "S1 Volts AB"}, //0.1x
{HR_LONG, 50022, 0, "S1 Volts AN"}, {HR_LONG, 50022, 0, "S1 Volts AN"}, //0.1x
{HR_LONG, 50025, 0, "S1 Volts BC"}, {HR_LONG, 50025, 0, "S1 Volts BC"}, //0.1x
{HR_LONG, 50028, 0, "S1 Volts BN"}, {HR_LONG, 50028, 0, "S1 Volts BN"}, //0.1x
{HR_LONG, 50031, 0, "S1 Volts CA"}, {HR_LONG, 50031, 0, "S1 Volts CA"}, //0.1x
{HR_LONG, 50034, 0, "S1 Volts CN"}, {HR_LONG, 50034, 0, "S1 Volts CN"}, //0.1x
{HR_LONG, 50037, 0, "S2 Amps A"}, {HR_LONG, 50037, 0, "S2 Amps A"}, //0.001x
{HR_LONG, 50040, 0, "S2 Amps B"}, {HR_LONG, 50040, 0, "S2 Amps B"}, //0.001x
{HR_LONG, 50043, 0, "S2 Amps C"}, {HR_LONG, 50043, 0, "S2 Amps C"}, //0.001x
{HR_LONG, 50060, 0, "S2 kW"}, {HR_LONG, 50060, 0, "S2 kW"},
{HR_LONG, 50064, 0, "S2 MWh"}, {HR_LONG, 50064, 0, "S2 MWh"}, //0.01x
{HR, 50078, 0, "Source Preferred"}, // bit 8 and bit 9 {HR, 50078, 0, "Source Preferred"}, //bit9 source1 bit8 source 2
{HR, 50082, 0, "Source Active"}, //bit2 and bit 3 {HR, 50082, 0, "Source Active"}, //bit4 source1 bit3 source 2
{HR_LONG, 50091, 0, "S1 Amps A"}, {HR_LONG, 50091, 0, "S1 Amps A"}, //.001x
{HR, 50093, 0, "S1 kW"}, {HR, 50093, 0, "S1 kW"}, //.1x
{HR_LONG, 50094, 0, "S1 Amps B"}, {HR_LONG, 50094, 0, "S1 Amps B"}, //.001x
{HR_LONG, 50097, 0, "S1 Amps C"}, {HR_LONG, 50097, 0, "S1 Amps C"}, //.001x
{HR_LONG, 50100, 0, "S1 MWh"}, {HR_LONG, 50100, 0, "S1 MWh"}, //.01x
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.

View File

@@ -38,11 +38,11 @@
*/ */
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("Volts AB", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Volts AB", new SingleValueStrategy(4800.0F, 5.0f, 1000));
addStrategy("Volts BC", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Volts BC", new SingleValueStrategy(4800.0F, 5.0f, 1000));
addStrategy("Volts CA", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Volts CA", new SingleValueStrategy(4800.0F, 5.0f, 1000));
addStrategy("PF", new SingleValueStrategy(90.0f, 1.0f, 1000)); addStrategy("PF", new SingleValueStrategy(900.0f, 1.0f, 1000));
addStrategy("Amps A", new SingleValueStrategy(1.0f, 10.0f, 1000)); addStrategy("Amps A", new SingleValueStrategy(1.0f, 10.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 10.0f, 1000)); addStrategy("Amps B", new SingleValueStrategy(1.0f, 10.0f, 1000));
@@ -66,9 +66,11 @@ template<>
State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment) { State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Running update function"); Serial.println("Running update function");
Serial.println("Running update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 1){ if (State_Ctrl == 0.0f){
return new StandbyState<ModbusIP>();
}
if (State_Ctrl == 2.0f){
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
@@ -76,9 +78,9 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
float volts_BC = getPointValue(equipment, "Volts BC"); float volts_BC = getPointValue(equipment, "Volts BC");
float volts_AC = getPointValue(equipment, "Volts CA"); float volts_AC = getPointValue(equipment, "Volts CA");
setPointValue(equipment, "Volts AN", volts_AB/1.732); setPointValue(equipment, "Volts AN", volts_AB/1.732f);
setPointValue(equipment, "Volts BN", volts_BC/1.732); setPointValue(equipment, "Volts BN", volts_BC/1.732f);
setPointValue(equipment, "Volts CN", volts_AC/1.732); setPointValue(equipment, "Volts CN", volts_AC/1.732f);
int I_load = getPointValue(equipment, "Load"); int I_load = getPointValue(equipment, "Load");
@@ -86,18 +88,21 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
float load = static_cast<float>(I_load); float load = static_cast<float>(I_load);
float rating = static_cast<float>(I_rating); float rating = static_cast<float>(I_rating);
float real_load = rating * (load/100.0f); float real_load = rating * (load/100.0f);
setPointValue(equipment, "Amps A", real_load); setPointValue(equipment, "Amps A", real_load * 10.0f);
setPointValue(equipment, "Amps B", real_load); setPointValue(equipment, "Amps B", real_load * 10.0f);
setPointValue(equipment, "Amps C", real_load); setPointValue(equipment, "Amps C", real_load * 10.0f);
setPointValue(equipment, "Amps G", volts_AB * 0.037f);
setPointValue(equipment, "Amps N", volts_BC * 0.034f);
float pf = getPointValue(equipment, "PF"); float pf = getPointValue(equipment, "PF");
float kw = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load * (pf/100))/100; float kva = (1.732f * ((volts_AB + volts_BC + volts_AC)/4.0f) * real_load * (pf/100.0f))/100000.0f;
float kva = (1.732f * ((volts_AB + volts_BC + volts_AC)/3.0f) * real_load)/100; float kw = (1.732f * ((volts_AB + volts_BC + volts_AC)/4.0f) * real_load )/10000.0f;
setPointValue(equipment, "kW", kw); setPointValue(equipment, "kW", kw);
setPointValue(equipment, "kVA", kva); setPointValue(equipment, "kVA", kva);
setPointValue(equipment, "kWh", 1724.0f);
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
@@ -113,7 +118,8 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
setPointValue(equipment, "CB Position", 1); setBitValue(equipment, "CB Position", 0, true);
setBitValue(equipment, "CB Position", 12, false);
} }
/** /**

View File

@@ -57,9 +57,16 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function"); Serial.println("Standby update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 2){ if (State_Ctrl == 1.0f){
return new RunningState<ModbusIP>(); return new RunningState<ModbusIP>();
} }
if (State_Ctrl == 0.0f){
setBitValue(equipment, "CB Position", 12, false);
}
if (State_Ctrl == 2.0f){
setBitValue(equipment, "CB Position", 12, true);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
@@ -75,7 +82,7 @@ template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "CB Position", 0); setBitValue(equipment, "CB Position", 0, false);
setPointValue(equipment, "Volts AB", 0.0f); setPointValue(equipment, "Volts AB", 0.0f);
setPointValue(equipment, "Volts BC", 0.0f); setPointValue(equipment, "Volts BC", 0.0f);
setPointValue(equipment, "Volts CA", 0.0f); setPointValue(equipment, "Volts CA", 0.0f);
@@ -86,8 +93,11 @@ void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "Amps A", 0.0f); setPointValue(equipment, "Amps A", 0.0f);
setPointValue(equipment, "Amps B", 0.0f); setPointValue(equipment, "Amps B", 0.0f);
setPointValue(equipment, "Amps C", 0.0f); setPointValue(equipment, "Amps C", 0.0f);
setPointValue(equipment, "Amps G", 0.0f);
setPointValue(equipment, "Amps N", 0.0f);
setPointValue(equipment, "kW", 0.0f); setPointValue(equipment, "kW", 0.0f);
setPointValue(equipment, "kVA", 0.0f); setPointValue(equipment, "kVA", 0.0f);
setPointValue(equipment, "kWh", 0.0f);
} }
/** /**

View File

@@ -23,8 +23,8 @@
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "123abc456"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(172, 17, 30, 241); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 154); /**< @brief The static IP address for the device. */
IPAddress gateway(172, 17, 30, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;
@@ -63,7 +63,7 @@ modbusMap mb_map[] =
{HR, 9, 0, "State Control"}, //Open-Close Cmd {HR, 9, 0, "State Control"}, //Open-Close Cmd
{HR, 10, 0, "Load"}, //Adjustble Load {HR, 10, 0, "Load"}, //Adjustble Load
{HR, 11, 0, "Rating"}, //Max amp to calculate kw, kVA, etc {HR, 11, 0, "Rating"}, //Max amp to calculate kw, kVA, etc
{IR_LONG, 41, 0, "CB Position"}, {IR, 41, 0, "CB Position"}, //b0 close open b12 tripped
{IR_LONG, 101, 0, "Amps A"}, {IR_LONG, 101, 0, "Amps A"},
{IR_LONG, 103, 0, "Amps B"}, {IR_LONG, 103, 0, "Amps B"},
{IR_LONG, 105, 0, "Amps C"}, {IR_LONG, 105, 0, "Amps C"},

View File

@@ -68,7 +68,10 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Running update function"); Serial.println("Running update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 1){ if (State_Ctrl == 0){
return new StandbyState<ModbusIP>();
}
if (State_Ctrl == 2){
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
@@ -118,6 +121,7 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
setPointValue(equipment, "CB Position", 2048); setPointValue(equipment, "CB Position", 2048);
setPointValue(equipment, "CB Trip", 0.0f);
} }

View File

@@ -57,9 +57,16 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function"); Serial.println("Standby update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 2){ if (State_Ctrl == 1){
return new RunningState<ModbusIP>(); return new RunningState<ModbusIP>();
} }
if (State_Ctrl == 0){
setPointValue(equipment, "CB Trip", 0.0f);
}
if (State_Ctrl == 2){
setPointValue(equipment, "CB Trip", 1.0f);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -21,10 +21,10 @@
* @{ * @{
*/ */
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "wifi_name"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "wifi_password"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(192, 168, 1, 234); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 167); /**< @brief The static IP address for the device. */
IPAddress gateway(192, 168, 1, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;

View File

@@ -61,7 +61,10 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Running update function"); Serial.println("Running update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 1){ if (State_Ctrl == 0.0f){
return new StandbyState<ModbusIP>();
}
if (State_Ctrl == 2.0f){
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
@@ -92,7 +95,9 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
setPointValue(equipment, "Status", 4);
setBitValue(equipment, "Status", 2, true);
setBitValue(equipment, "Tripped", 0, false);
} }

View File

@@ -57,9 +57,16 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function"); Serial.println("Standby update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 2){ if (State_Ctrl == 1.0f){
return new RunningState<ModbusIP>(); return new RunningState<ModbusIP>();
} }
if (State_Ctrl == 0.0f){
setBitValue(equipment, "Tripped", 0, false);
}
if (State_Ctrl == 2.0f){
setBitValue(equipment, "Tripped", 0, true);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
@@ -75,11 +82,13 @@ template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "Status", 0);
setPointValue(equipment, "Amps A", 0.0f); setPointValue(equipment, "Amps A", 0.0f);
setPointValue(equipment, "Amps B", 0.0f); setPointValue(equipment, "Amps B", 0.0f);
setPointValue(equipment, "Amps C", 0.0f); setPointValue(equipment, "Amps C", 0.0f);
setPointValue(equipment, "Amps N", 0.0f);
setBitValue(equipment, "Status", 2, false);
} }
/** /**

View File

@@ -21,10 +21,10 @@
* @{ * @{
*/ */
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "wifi_name"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "wifi_password"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(192, 168, 1, 238); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 149); /**< @brief The static IP address for the device. */
IPAddress gateway(192, 138, 1, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;
@@ -64,11 +64,12 @@ modbusMap mb_map[] =
{HR, 10, 0, "Load"}, {HR, 10, 0, "Load"},
{HR, 11, 0, "Rating"}, {HR, 11, 0, "Rating"},
{IR, 2, 0, "Status"}, {IR, 2, 0, "Status"}, //bit 2 open-close,
{IR, 3, 0, "Amps A"}, {IR, 3, 0, "Amps A"},
{IR, 5, 0, "Amps B"}, {IR, 5, 0, "Amps B"},
{IR, 7, 0, "Amps C"}, {IR, 7, 0, "Amps C"},
{IR, 9, 0, "Amps N"}, {IR, 9, 0, "Amps N"},
{IR, 13, 0, "Tripped"}, //bit 0 tripped
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.

View File

@@ -68,7 +68,10 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Running update function"); Serial.println("Running update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 1){ if (State_Ctrl == 0.0f){
return new StandbyState<ModbusIP>();
}
if (State_Ctrl == 2.0f){
return new StandbyState<ModbusIP>(); return new StandbyState<ModbusIP>();
} }
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
@@ -116,7 +119,9 @@ void RunningState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Running State..."); Serial.println("Enter Running State...");
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
setPointValue(equipment, "CB Position", 4096);
setBitValue(equipment, "CB Position", 12, true);
setBitValue(equipment, "CB Position", 9, false);
} }

View File

@@ -57,9 +57,17 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
// STATE control, add conditions if change to a different state is needed // STATE control, add conditions if change to a different state is needed
Serial.println("Standby update function"); Serial.println("Standby update function");
float State_Ctrl = getPointValue(equipment, "State Control"); float State_Ctrl = getPointValue(equipment, "State Control");
if (State_Ctrl == 2){ if (State_Ctrl == 1.0f){
return new RunningState<ModbusIP>(); return new RunningState<ModbusIP>();
} }
if (State_Ctrl == 0.0f){
setBitValue(equipment, "CB Position", 9, false);
}
if (State_Ctrl == 2.0f){
setBitValue(equipment, "CB Position", 9, true);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
@@ -86,6 +94,7 @@ void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "Amps A", 0.0f); setPointValue(equipment, "Amps A", 0.0f);
setPointValue(equipment, "Amps B", 0.0f); setPointValue(equipment, "Amps B", 0.0f);
setPointValue(equipment, "Amps C", 0.0f); setPointValue(equipment, "Amps C", 0.0f);
setBitValue(equipment, "CB Position", 12, false);
} }
/** /**

View File

@@ -23,7 +23,7 @@
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "123abc456"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(172, 17, 33, 132); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 141); /**< @brief The static IP address for the device. */
IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
@@ -64,7 +64,7 @@ modbusMap mb_map[] =
{HR, 10, 0, "Load"}, {HR, 10, 0, "Load"},
{HR, 11, 0, "Rating"}, {HR, 11, 0, "Rating"},
{IR, 207, 0, "CB Position"}, {IR, 207, 0, "CB Position"}, //bit 9 trip bit 12 open closed
{IR_FLOAT, 215, 0, "Amps A"}, {IR_FLOAT, 215, 0, "Amps A"},
{IR_FLOAT, 217, 0, "Amps B"}, {IR_FLOAT, 217, 0, "Amps B"},
{IR_FLOAT, 219, 0, "Amps C"}, {IR_FLOAT, 219, 0, "Amps C"},

View File

@@ -36,80 +36,90 @@
* state, such as a PID controller for the 'CW Valve Position' and totalizers * state, such as a PID controller for the 'CW Valve Position' and totalizers
* for the run-hours of each EC fan. * for the run-hours of each EC fan.
*/ */
std::string cbs[] = {"CB0", "CB1", "CB2", "CB3", "CB4", "CB5", "CB6", "CB7", "CB8", "CB9"}; std::string cbs[] = {"CB1", "CB2", "CB3", "CB4", "CB5", "CB6", "CB7", "CB8"};
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("Input_I1", new SingleValueStrategy(40.0f, 30.0f, 1000));
addStrategy("Input_I2", new SingleValueStrategy(40.0f, 30.0f, 1000));
addStrategy("Input_I3", new SingleValueStrategy(40.0f, 30.0f, 1000));
addStrategy("Input_kVA", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Input_kVAR", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Input_kW", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Input_kWh", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_PF", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Input_V_AB", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_V_AN", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_V_BC", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_V_BN", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_V_CA", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_V_CN", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_LL_Avg", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Input_LN_Avg", new SingleValueStrategy(3.0f, 2.0f, 1000));
for (const std::string& cb : cbs) { for (const std::string& cb : cbs) {
std::string tag = ""; std::string tag = "";
tag = cb + "_V1N";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000));
tag = ""; tag = "";
tag = cb + "_V2N"; tag = cb + "_I1";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000)); addStrategy(tag, new SingleValueStrategy(40.0f, 30.0f, 1000));
tag = ""; tag = "";
tag = cb + "_V3N"; tag = cb + "_I2";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000)); addStrategy(tag, new SingleValueStrategy(40.0f, 30.0f, 1000));
tag = ""; tag = "";
tag = cb + "_L1PF"; tag = cb + "_I3";
addStrategy(tag, new SingleValueStrategy(93.0f, 9.0f, 1000)); addStrategy(tag, new SingleValueStrategy(40.0f, 30.0f, 1000));
tag = ""; tag = "";
tag = cb + "_L2PF"; tag = cb + "_kVA";
addStrategy(tag, new SingleValueStrategy(93.0f, 9.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_L3PF"; tag = cb + "_kVA1";
addStrategy(tag, new SingleValueStrategy(93.0f, 9.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_V1THD"; tag = cb + "_kVA2";
addStrategy(tag, new SingleValueStrategy(20.0f, 7.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_V2THD"; tag = cb + "_kVA3";
addStrategy(tag, new SingleValueStrategy(20.0f, 7.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_V3THD"; tag = cb + "_kVAR";
addStrategy(tag, new SingleValueStrategy(20.0f, 7.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = "";
tag = cb + "_I1THD";
addStrategy(tag, new SingleValueStrategy(100.0f, 12.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I2THD"; tag = cb + "_kW";
addStrategy(tag, new SingleValueStrategy(100.0f, 12.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I3THD"; tag = cb + "_kW1";
addStrategy(tag, new SingleValueStrategy(100.0f, 12.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I1Kfactor"; tag = cb + "_kW2";
addStrategy(tag, new SingleValueStrategy(30.0f, 6.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I2Kfactor"; tag = cb + "_kW3";
addStrategy(tag, new SingleValueStrategy(30.0f, 6.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I3Kfactor"; tag = cb + "_kWh";
addStrategy(tag, new SingleValueStrategy(30.0f, 6.0f, 1000)); addStrategy(tag, new SingleValueStrategy(0.1f, 100.0f, 1000));
tag = ""; tag = "";
tag = cb + "_I1TDD"; tag = cb + "_PF";
addStrategy(tag, new SingleValueStrategy(50.0f, 9.0f, 1000)); addStrategy(tag, new SingleValueStrategy(150.0f, 100.0f, 1000));
tag = "";
tag = cb + "_I2TDD";
addStrategy(tag, new SingleValueStrategy(50.0f, 9.0f, 1000));
tag = "";
tag = cb + "_I3TDD";
addStrategy(tag, new SingleValueStrategy(50.0f, 9.0f, 1000));
tag = "";
tag = cb + "_V12";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000));
tag = "";
tag = cb + "_V23";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000));
tag = "";
tag = cb + "_V31";
addStrategy(tag, new SingleValueStrategy(0.0f, 30.0f, 1000));
} }
addStrategy("Amps G", new SingleValueStrategy(0.0f, 2.0f, 1000));
addStrategy("Amps N", new SingleValueStrategy(0.0f, 3.0f, 1000)); addStrategy("Output_I1", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("kWh", new RampStrategy(5000000.0f, 1.0f, 1000)); addStrategy("Output_I2", new SingleValueStrategy(30.0f, 30.0f, 1000));
addStrategy("PF", new SingleValueStrategy(0.0f, 1.0f, 1000)); addStrategy("Output_I3", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("Output_IG", new SingleValueStrategy(30.0f, 30.0f, 1000));
addStrategy("Output_IN", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("Output_kVA1", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Output_kVA2", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Output_kVA3", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Output_kWh", new SingleValueStrategy(3.0f, 2.0f, 1000));
addStrategy("Output_PF", new SingleValueStrategy(150.0f, 100.0f, 1000));
addStrategy("Output_V_AB", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("Output_V_AN", new SingleValueStrategy(30.0f, 30.0f, 1000));
addStrategy("Output_V_BC", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("Output_V_BN", new SingleValueStrategy(30.0f, 30.0f, 1000));
addStrategy("Output_V_CA", new SingleValueStrategy(30.0f, 20.0f, 1000));
addStrategy("Output_V_CN", new SingleValueStrategy(30.0f, 30.0f, 1000));
} }
/** /**
@@ -140,14 +150,14 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
float cb_count = 0.0f; float cb_count = 0.0f;
for (const std::string& cb :cbs){ for (const std::string& cb :cbs){
std::string tag = ""; std::string tag = "";
tag = "Px " + cb; tag = "Px_" + cb;
if (cb == "CB0") continue;
float cb_status = getPointValue(equipment, tag); float cb_status = getPointValue(equipment, tag);
if (cb_status == 1.0f){ if (cb_status == 1.0f){
cb_count += 1.0f; cb_count += 1.0f;
} }
} }
int cb_num = 0; Serial.printf("CB_ CLosed = %f \n", cb_count);
int cb_num = 1;
for (const std::string& cb : cbs) { for (const std::string& cb : cbs) {
std::string tag = ""; std::string tag = "";
Strategy_Behavior* strategy = nullptr; Strategy_Behavior* strategy = nullptr;
@@ -156,140 +166,224 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
float cb_status = getPointValue(equipment, tag); float cb_status = getPointValue(equipment, tag);
float percent_load = getPointValue(equipment, "Px Load"); float percent_load = getPointValue(equipment, "Px Load");
float Rating = getPointValue(equipment, "Px Rating"); float Rating = getPointValue(equipment, "Px Rating");
float total_load = Rating * (percent_load /100.0f); float cb_load = 400.0f * (percent_load /1000.0f);
float cb_load = total_load / cb_count;
if (cb_status == 1.0f){ if (cb_status == 1.0f){
setBitValue(equipment, "CB_Status", cb_num, true); setBitValue(equipment, "CB_Status", cb_num, true);
strategy = getStrategy("Amps G"); setBitValue(equipment, "CB_Tripped", cb_num, false);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(65.0f);
strategy = getStrategy("Amps N");
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(50.0f);
strategy = getStrategy("PF");
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(90.0f);
tag = "";
tag = cb + "_V1N";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(2700.0f);
tag = "";
tag = cb + "_V2N";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(2700.0f);
tag = "";
tag = cb + "_V3N";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(2700.0f);
tag = "";
tag = cb + "_V12";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(4800.0f);
tag = "";
tag = cb + "_V23";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(4800.0f);
tag = "";
tag = cb + "_V31";
strategy = getStrategy(tag);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(4800.0f);
tag = ""; tag = "";
tag = cb + "_I1"; tag = cb + "_I1";
setPointValue(equipment, tag, total_load * 100.0f); setPointValue(equipment, tag, cb_load * 1000.0f);
tag = ""; tag = "";
tag = cb + "_I2"; tag = cb + "_I2";
setPointValue(equipment, tag, total_load * 100.0f); setPointValue(equipment, tag, cb_load * 1000.0f);
tag = ""; tag = "";
tag = cb + "_I3"; tag = cb + "_I3";
setPointValue(equipment, tag, total_load * 100.0f); setPointValue(equipment, tag, cb_load * 1000.0f);
tag = "";
tag = cb + "_PF";
setPointValue(equipment, tag, 910.0f);
tag = "";
tag = cb + "_PF";
float pf = getPointValue(equipment, tag);
tag = ""; tag = "";
tag = cb + "_L1KW"; tag = cb + "_kW1";
setPointValue(equipment, tag, total_load * 1715.0f); setPointValue(equipment, tag, cb_load * 48000.0f * pf);
float kW1 = getPointValue(equipment, tag);
tag = ""; tag = "";
tag = cb + "_L2KW"; tag = cb + "_kW2";
setPointValue(equipment, tag, total_load * 1715.0f); setPointValue(equipment, tag, cb_load * 48000.0f * pf);
float kW2 = getPointValue(equipment, tag);
tag = ""; tag = "";
tag = cb + "_L3KW"; tag = cb + "_kW3";
setPointValue(equipment, tag, total_load * 1715.0f); setPointValue(equipment, tag, cb_load * 48000.0f * pf);
float kW3 = getPointValue(equipment, tag);
tag = "";
tag = cb + "_kW";
setPointValue(equipment, tag, ((kW1 + kW2 + kW3) / 3.0f)*1000.0f);
tag = "";
tag = cb + "_kWh";
setPointValue(equipment, tag, 1325.0f);
tag = "";
tag = cb + "_kVA";
setPointValue(equipment, tag, cb_load * 480.0f * 10000.0f);
tag = "";
tag = cb + "_kVA";
setPointValue(equipment, tag, cb_load * 480.0f * 10000.0f);
tag = "";
tag = cb + "_kVA";
setPointValue(equipment, tag, cb_load * 480.0f * 10000.0f);
tag = ""; tag = "";
tag = cb + "_L1KVar"; tag = cb + "_kVA1";
setPointValue(equipment, tag, total_load * 1715.0f * 0.9f); float kVA1 = getPointValue(equipment, tag);
tag = ""; tag = "";
tag = cb + "_L2KVar"; tag = cb + "_kVA2";
setPointValue(equipment, tag, total_load * 1715.0f * 0.9f); float kVA2 = getPointValue(equipment, tag);
tag = ""; tag = "";
tag = cb + "_L3KVar"; tag = cb + "_kVA3";
setPointValue(equipment, tag, total_load * 1715.0f * 0.9f); float kVA3 = getPointValue(equipment, tag);
float kVA = (kVA1 + kVA2 + kVA3) * 1732.0f;
tag = "";
tag = cb + "_kVA";
setPointValue(equipment, tag, kVA);
tag = "";
tag = cb + "_kVAR";
setPointValue(equipment, tag, kVA / pf);
}else{ }
else{
if (cb_status == 2.0f){
setBitValue(equipment, "CB_Tripped", cb_num, true);
} else {
setBitValue(equipment, "CB_Tripped", cb_num, false);
}
setBitValue(equipment, "CB_Status", cb_num, false); setBitValue(equipment, "CB_Status", cb_num, false);
strategy = getStrategy("Amps G"); tag = "";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = cb + "_I1";
strategy = getStrategy("Amps N"); setPointValue(equipment, tag, 40.0f);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = "";
strategy = getStrategy("PF"); tag = cb + "_I2";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); setPointValue(equipment, tag, 0.0f);
tag = ""; tag = "";
tag = cb + "_V1N"; tag = cb + "_I3";
strategy = getStrategy(tag); setPointValue(equipment, tag, 40.0f);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = "";
tag = ""; tag = cb + "_kVA";
tag = cb + "_V2N"; setPointValue(equipment, tag, 150.0f);
strategy = getStrategy(tag); tag = "";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = cb + "_kVA1";
tag = ""; setPointValue(equipment, tag, 150.0f);
tag = cb + "_V3N"; tag = "";
strategy = getStrategy(tag); tag = cb + "_kVA2";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); setPointValue(equipment, tag, 150.0f);
tag = "";
tag = ""; tag = cb + "_kVA3";
tag = cb + "_V12"; setPointValue(equipment, tag, 150.0f);
strategy = getStrategy(tag); tag = "";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = cb + "_kVAR";
tag = ""; setPointValue(equipment, tag, 150.0f);
tag = cb + "_V23"; tag = "";
strategy = getStrategy(tag); tag = cb + "_kW";
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); setPointValue(equipment, tag, 150.0f);
tag = ""; tag = "";
tag = cb + "_V31"; tag = cb + "_kW1";
strategy = getStrategy(tag); setPointValue(equipment, tag, 150.0f);
static_cast<SingleValueStrategy*>(strategy)->setSetpoint(0.0f); tag = "";
tag = cb + "_kW2";
tag = ""; setPointValue(equipment, tag, 150.0f);
tag = cb + "_I1"; tag = "";
setPointValue(equipment, tag, total_load); tag = cb + "_kW3";
tag = ""; setPointValue(equipment, tag, 150.0f);
tag = cb + "_I2"; tag = "";
setPointValue(equipment, tag, total_load); tag = cb + "_kWh";
tag = ""; setPointValue(equipment, tag, 0.5f);
tag = cb + "_I3"; tag = "";
setPointValue(equipment, tag, total_load); tag = cb + "_PF";
setPointValue(equipment, tag, 150.0f);
tag = "";
tag = cb + "_L1KW";
setPointValue(equipment, tag, total_load*0.0f);
tag = "";
tag = cb + "_L2KW";
setPointValue(equipment, tag, total_load*0.0f);
tag = "";
tag = cb + "_L3KW";
setPointValue(equipment, tag, total_load*0.0f);
tag = "";
tag = cb + "_L1KVar";
setPointValue(equipment, tag, total_load*0.0f);
tag = "";
tag = cb + "_L2KVar";
setPointValue(equipment, tag, total_load*0.0f);
tag = "";
tag = cb + "_L3KVar";
setPointValue(equipment, tag, total_load*0.0f);
} }
cb_num++; cb_num++;
} }
Serial.printf("CB_ CLosed = %f \n", cb_count);
if (cb_count > 0.0f){
Serial.println("At least one breaker closed...");
float percent_load = getPointValue(equipment, "Px Load");
float cb_load = 400.0f * (percent_load /1000.0f);
setPointValue(equipment, "Input_I1", cb_count * cb_load *100.0f);
setPointValue(equipment, "Input_I2", cb_count * cb_load *100.0f);
setPointValue(equipment, "Input_I3", cb_count * cb_load *100.0f);
setPointValue(equipment, "Output_I1", cb_count * cb_load *100.0f);
setPointValue(equipment, "Output_I2", cb_count * cb_load*100.0f);
setPointValue(equipment, "Output_I3", cb_count * cb_load*100.0f);
setPointValue(equipment, "Output_IG", cb_count * 750.0f);
setPointValue(equipment, "Output_IN", cb_count * 482.0f);
float pf = 0.92f;
setPointValue(equipment, "Input_PF", pf * 930.0f);
setPointValue(equipment, "Output_PF", pf);
float i1 = getPointValue(equipment, "Input_I1");
float i2 = getPointValue(equipment, "Input_I2");
float i3 = getPointValue(equipment, "Input_I3");
setPointValue(equipment, "Input_kW", 480.0f * ((i1 + i2 + i3) / 3.0f));
float kW = getPointValue(equipment, "Input_kW");
setPointValue(equipment, "Input_kVA", kW * 1.732f);
setPointValue(equipment, "Output_kVA1", (kW * 1.732f)/3.0f);
setPointValue(equipment, "Output_kVA2", (kW * 1.732f)/3.0f);
setPointValue(equipment, "Output_kVA3", (kW * 1.732f)/3.0f);
setPointValue(equipment, "Input_kVAR", kW * 1.732f* pf);
setPointValue(equipment, "Output_kVAR", kW * 1.732f* pf);
setPointValue(equipment, "Output_kW1", kW /3.0f);
setPointValue(equipment, "Output_kW2", kW /3.0f);
setPointValue(equipment, "Output_kW3", kW /3.0f);
setPointValue(equipment, "Output_kWh", 1423.0f);
setPointValue(equipment, "Input_V_AB", 4800.0f);
setPointValue(equipment, "Input_V_AN", 2700.0f);
setPointValue(equipment, "Input_V_BC", 4800.0f);
setPointValue(equipment, "Input_V_BN", 2700.0f);
setPointValue(equipment, "Input_V_CA", 4800.0f);
setPointValue(equipment, "Input_V_CN", 2700.0f);
setPointValue(equipment, "Input_LL_Avg", 4800.0f);
setPointValue(equipment, "Input_LN_Avg", 2700.0f);
setPointValue(equipment, "Output_V_AB", 4800.0f);
setPointValue(equipment, "Output_V_AN", 2700.0f);
setPointValue(equipment, "Output_V_BC", 4800.0f);
setPointValue(equipment, "Output_V_BN", 2700.0f);
setPointValue(equipment, "Output_V_CA", 4800.0f);
setPointValue(equipment, "Output_V_CN", 2700.0f);
} else {
Serial.println("No breaker closed...");
setPointValue(equipment, "Input_I1", 50.0f);
setPointValue(equipment, "Input_I2", 50.0f);
setPointValue(equipment, "Input_I3", 50.0f);
setPointValue(equipment, "Output_I1", 50.0f);
setPointValue(equipment, "Output_I2", 50.0f);
setPointValue(equipment, "Output_I3", 50.0f);
setPointValue(equipment, "Output_IG", 50.0f);
setPointValue(equipment, "Output_IN", 50.0f);
setPointValue(equipment, "Input_PF", 0.0f);
setPointValue(equipment, "Output_PF", 0.0f);
setPointValue(equipment, "Input_kW", 0.0f);
setPointValue(equipment, "Input_kVA", 0.0f);
setPointValue(equipment, "Output_kVA1", 0.0f);
setPointValue(equipment, "Output_kVA2", 0.0f);
setPointValue(equipment, "Output_kVA3", 0.0f);
setPointValue(equipment, "Input_kVAR", 0.0f);
setPointValue(equipment, "Output_kVAR", 0.0f);
setPointValue(equipment, "Output_kW1", 0.0f);
setPointValue(equipment, "Output_kW2", 0.0f);
setPointValue(equipment, "Output_kW3", 0.0f);
setPointValue(equipment, "Output_kWh", 1.0f);
setPointValue(equipment, "Input_V_AB", 4800.0f);
setPointValue(equipment, "Input_V_AN", 2700.0f);
setPointValue(equipment, "Input_V_BC", 4800.0f);
setPointValue(equipment, "Input_V_BN", 2700.0f);
setPointValue(equipment, "Input_V_CA", 4800.0f);
setPointValue(equipment, "Input_V_CN", 2700.0f);
setPointValue(equipment, "Input_LL_Avg", 4800.0f);
setPointValue(equipment, "Input_LN_Avg", 2700.0f);
setPointValue(equipment, "Output_V_AB", 10.0f);
setPointValue(equipment, "Output_V_AN", 10.0f);
setPointValue(equipment, "Output_V_BC", 10.0f);
setPointValue(equipment, "Output_V_BN", 10.0f);
setPointValue(equipment, "Output_V_CA", 10.0f);
setPointValue(equipment, "Output_V_CN", 10.0f);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;

View File

@@ -79,6 +79,16 @@ template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "Input_V_AB", 0.0f);
setPointValue(equipment, "Input_V_AN", 0.0f);
setPointValue(equipment, "Input_V_BC", 0.0f);
setPointValue(equipment, "Input_V_BN", 0.0f);
setPointValue(equipment, "Input_V_CA", 0.0f);
setPointValue(equipment, "Input_V_CN", 0.0f);
setPointValue(equipment, "Input_LL_Avg", 0.0f);
setPointValue(equipment, "Input_LN_Avg", 0.0f);
setPointValue(equipment, "Output_PF", 0.0f);
} }
/** /**

View File

@@ -22,8 +22,8 @@
*/ */
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "123abc456"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(172, 17, 33, 178); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 181); /**< @brief The static IP address for the device. */
IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
@@ -46,8 +46,6 @@
ModbusRTU mb; ModbusRTU mb;
#endif #endif
/** /**
* @defgroup ModbusMapConfig Modbus Map Configuration * @defgroup ModbusMapConfig Modbus Map Configuration
* @brief Defines the Modbus register map and related parameters for the emulator. * @brief Defines the Modbus register map and related parameters for the emulator.
@@ -64,9 +62,9 @@ modbusMap mb_map[] = {
// Write Registers (as Input Registers - 3X) // Write Registers (as Input Registers - 3X)
//*************************************** //***************************************
{HR, 9, 0, "Px Ctrl"}, {HR, 9, 0, "Px Ctrl"},
{HR, 10, 0, "Px Rating"}, //Watts {HR, 10, 0, "Px Rating"}, //Amps
{HR, 11, 0, "Px Load"}, //%load {HR, 11, 0, "Px Load"}, //%load
{HR, 19, 0, "Px_CB0"}, {HR, 19, 0, "Px_Input"},
{HR, 20, 0, "Px_CB1"}, {HR, 20, 0, "Px_CB1"},
{HR, 21, 0, "Px_CB2"}, {HR, 21, 0, "Px_CB2"},
{HR, 22, 0, "Px_CB3"}, {HR, 22, 0, "Px_CB3"},
@@ -75,497 +73,178 @@ modbusMap mb_map[] = {
{HR, 25, 0, "Px_CB6"}, {HR, 25, 0, "Px_CB6"},
{HR, 26, 0, "Px_CB7"}, {HR, 26, 0, "Px_CB7"},
{HR, 27, 0, "Px_CB8"}, {HR, 27, 0, "Px_CB8"},
{HR, 28, 0, "Px_CB9"}, {HR, 28, 0, "Px_Output"},
// System Status // PDU Input
{IR_LONG, 0, 0, "CB0_V1N" }, {IR_LONG, 6, 0, "Input_I1" }, //0.01
{IR_LONG, 2, 0, "CB0_V2N" }, {IR_LONG, 8, 0, "Input_I2" }, //0.01
{IR_LONG, 4, 0, "CB0_V3N" }, {IR_LONG, 10, 0, "Input_I3" }, //0.01
{IR_LONG, 6, 0, "CB0_I1" }, {IR_LONG, 70, 0, "Input_kVA" }, //0.001
{IR_LONG, 8, 0, "CB0_I2" }, {IR_LONG, 68, 0, "Input_KVAR" }, //0.001
{IR_LONG, 10, 0, "CB0_I3" }, {IR_LONG, 66, 0, "Input_kW" }, //0.001
{IR_LONG, 12, 0, "CB0_L1KW" }, {IR_LONG, 66, 0, "Input_kWh" }, //0.1
{IR_LONG, 14, 0, "CB0_L2KW" }, {IR_LONG, 72, 0, "Input_PF" }, //0.001
{IR_LONG, 16, 0, "CB0_L3KW" }, {IR_LONG, 60, 0, "Input_V_AB" }, //0.1
{IR_LONG, 18, 0, "CB0_L1KVar" }, {IR_LONG, 0, 0, "Input_V_AN" }, //0.1
{IR_LONG, 20, 0, "CB0_L2KVar" }, {IR_LONG, 62, 0, "Input_V_BC" }, //0.1
{IR_LONG, 22, 0, "CB0_L3KVar" }, {IR_LONG, 2, 0, "Input_V_BN" }, //0.1
{IR_LONG, 24, 0, "CB0_L1KVA" }, {IR_LONG, 64, 0, "Input_V_CA" }, //0.1
{IR_LONG, 26, 0, "CB0_L2KVA" }, {IR_LONG, 4, 0, "Input_V_CN" }, //0.1
{IR_LONG, 28, 0, "CB0_L3KVA" }, {IR_LONG, 88, 0, "Input_LL_Avg" },//0.1
{IR_LONG, 30, 0, "CB0_L1PF" }, {IR_LONG, 86, 0, "Input_LN_Avg" },//0.1
{IR_LONG, 32, 0, "CB0_L2PF" },
{IR_LONG, 34, 0, "CB0_L3PF" },
{IR_LONG, 36, 0, "CB0_V1THD" },
{IR_LONG, 38, 0, "CB0_V2THD" },
{IR_LONG, 40, 0, "CB0_V3THD" },
{IR_LONG, 42, 0, "CB0_I1THD" },
{IR_LONG, 44, 0, "CB0_I2THD" },
{IR_LONG, 46, 0, "CB0_I3THD" },
{IR_LONG, 48, 0, "CB0_I1Kfactor" },
{IR_LONG, 50, 0, "CB0_I2Kfactor" },
{IR_LONG, 52, 0, "CB0_I3Kfactor" },
{IR_LONG, 54, 0, "CB0_I1TDD" },
{IR_LONG, 56, 0, "CB0_I2TDD" },
{IR_LONG, 58, 0, "CB0_I3TDD" },
{IR_LONG, 60, 0, "CB0_V12" },
{IR_LONG, 62, 0, "CB0_V23" },
{IR_LONG, 64, 0, "CB0_V31" },
{IR_LONG, 66, 0, "CB0_TotalKW" },
{IR_LONG, 68, 0, "CB0_TotalKVar" },
{IR_LONG, 70, 0, "CB0_TotalKVA" },
{IR_LONG, 72, 0, "CB0_TotalPF" },
{IR_LONG, 74, 0, "CB0_TotalPFLag" },
{IR_LONG, 76, 0, "CB0_TotalPFLead" },
{IR_LONG, 78, 0, "CB0_TotalKWImport" },
{IR_LONG, 80, 0, "CB0_TotalKWExport" },
{IR_LONG, 82, 0, "CB0_TotalKVarImport" },
{IR_LONG, 84, 0, "CB0_TotalKVarExport" },
{IR_LONG, 86, 0, "CB0_LN_Avg" },
{IR_LONG, 88, 0, "CB0_LL_Avg" },
{IR_LONG, 92, 0, "CB0_TotalKWh" },
{IR_LONG, 99, 0, "CB0_Status" },
// Circuit Breaker 1 (OB01)
{IR_LONG, 100, 0, "CB1_V1N" },
{IR_LONG, 102, 0, "CB1_V2N" },
{IR_LONG, 104, 0, "CB1_V3N" },
{IR_LONG, 106, 0, "CB1_I1" },
{IR_LONG, 108, 0, "CB1_I2" },
{IR_LONG, 110, 0, "CB1_I3" },
{IR_LONG, 112, 0, "CB1_L1KW" },
{IR_LONG, 114, 0, "CB1_L2KW" },
{IR_LONG, 116, 0, "CB1_L3KW" },
{IR_LONG, 118, 0, "CB1_L1KVar" },
{IR_LONG, 120, 0, "CB1_L2KVar" },
{IR_LONG, 122, 0, "CB1_L3KVar" },
{IR_LONG, 124, 0, "CB1_L1KVA" },
{IR_LONG, 126, 0, "CB1_L2KVA" },
{IR_LONG, 128, 0, "CB1_L3KVA" },
{IR_LONG, 130, 0, "CB1_L1PF" },
{IR_LONG, 132, 0, "CB1_L2PF" },
{IR_LONG, 134, 0, "CB1_L3PF" },
{IR_LONG, 136, 0, "CB1_V1THD" },
{IR_LONG, 138, 0, "CB1_V2THD" },
{IR_LONG, 140, 0, "CB1_V3THD" },
{IR_LONG, 142, 0, "CB1_I1THD" },
{IR_LONG, 144, 0, "CB1_I2THD" },
{IR_LONG, 146, 0, "CB1_I3THD" },
{IR_LONG, 148, 0, "CB1_I1Kfactor" },
{IR_LONG, 150, 0, "CB1_I2Kfactor" },
{IR_LONG, 152, 0, "CB1_I3Kfactor" },
{IR_LONG, 154, 0, "CB1_I1TDD" },
{IR_LONG, 156, 0, "CB1_I2TDD" },
{IR_LONG, 158, 0, "CB1_I3TDD" },
{IR_LONG, 160, 0, "CB1_V12" },
{IR_LONG, 162, 0, "CB1_V23" },
{IR_LONG, 164, 0, "CB1_V31" },
{IR_LONG, 166, 0, "CB1_TotalKW" },
{IR_LONG, 168, 0, "CB1_TotalKVar" },
{IR_LONG, 170, 0, "CB1_TotalKVA" },
{IR_LONG, 172, 0, "CB1_TotalPF" },
{IR_LONG, 174, 0, "CB1_TotalPFLag" },
{IR_LONG, 176, 0, "CB1_TotalPFLead" },
{IR_LONG, 178, 0, "CB1_TotalKWImport" },
{IR_LONG, 180, 0, "CB1_TotalKWExport" },
{IR_LONG, 182, 0, "CB1_TotalKVarImport" },
{IR_LONG, 184, 0, "CB1_TotalKVarExport" },
{IR_LONG, 186, 0, "CB1_LN_Avg" },
{IR_LONG, 188, 0, "CB1_LL_Avg" },
{IR_LONG, 199, 0, "CB1_Status" },
// Circuit Breaker 2 (OB02)
{IR_LONG, 200, 0, "CB2_V1N" },
{IR_LONG, 202, 0, "CB2_V2N" },
{IR_LONG, 204, 0, "CB2_V3N" },
{IR_LONG, 206, 0, "CB2_I1" },
{IR_LONG, 208, 0, "CB2_I2" },
{IR_LONG, 210, 0, "CB2_I3" },
{IR_LONG, 212, 0, "CB2_L1KW" },
{IR_LONG, 214, 0, "CB2_L2KW" },
{IR_LONG, 216, 0, "CB2_L3KW" },
{IR_LONG, 218, 0, "CB2_L1KVar" },
{IR_LONG, 220, 0, "CB2_L2KVar" },
{IR_LONG, 222, 0, "CB2_L3KVar" },
{IR_LONG, 224, 0, "CB2_L1KVA" },
{IR_LONG, 226, 0, "CB2_L2KVA" },
{IR_LONG, 228, 0, "CB2_L3KVA" },
{IR_LONG, 230, 0, "CB2_L1PF" },
{IR_LONG, 232, 0, "CB2_L2PF" },
{IR_LONG, 234, 0, "CB2_L3PF" },
{IR_LONG, 236, 0, "CB2_V1THD" },
{IR_LONG, 238, 0, "CB2_V2THD" },
{IR_LONG, 240, 0, "CB2_V3THD" },
{IR_LONG, 242, 0, "CB2_I1THD" },
{IR_LONG, 244, 0, "CB2_I2THD" },
{IR_LONG, 246, 0, "CB2_I3THD" },
{IR_LONG, 248, 0, "CB2_I1Kfactor" },
{IR_LONG, 250, 0, "CB2_I2Kfactor" },
{IR_LONG, 252, 0, "CB2_I3Kfactor" },
{IR_LONG, 254, 0, "CB2_I1TDD" },
{IR_LONG, 256, 0, "CB2_I2TDD" },
{IR_LONG, 258, 0, "CB2_I3TDD" },
{IR_LONG, 260, 0, "CB2_V12" },
{IR_LONG, 262, 0, "CB2_V23" },
{IR_LONG, 264, 0, "CB2_V31" },
{IR_LONG, 266, 0, "CB2_TotalKW" },
{IR_LONG, 268, 0, "CB2_TotalKVar" },
{IR_LONG, 270, 0, "CB2_TotalKVA" },
{IR_LONG, 272, 0, "CB2_TotalPF" },
{IR_LONG, 274, 0, "CB2_TotalPFLag" },
{IR_LONG, 276, 0, "CB2_TotalPFLead" },
{IR_LONG, 278, 0, "CB2_TotalKWImport" },
{IR_LONG, 280, 0, "CB2_TotalKWExport" },
{IR_LONG, 282, 0, "CB2_TotalKVarImport" },
{IR_LONG, 284, 0, "CB2_TotalKVarExport" },
{IR_LONG, 286, 0, "CB2_LN_Avg" },
{IR_LONG, 288, 0, "CB2_LL_Avg" },
{IR_LONG, 299, 0, "CB2_Status" },
// Circuit Breaker 3 (OB03)
{IR_LONG, 300, 0, "CB3_V1N" },
{IR_LONG, 302, 0, "CB3_V2N" },
{IR_LONG, 304, 0, "CB3_V3N" },
{IR_LONG, 306, 0, "CB3_I1" },
{IR_LONG, 308, 0, "CB3_I2" },
{IR_LONG, 310, 0, "CB3_I3" },
{IR_LONG, 312, 0, "CB3_L1KW" },
{IR_LONG, 314, 0, "CB3_L2KW" },
{IR_LONG, 316, 0, "CB3_L3KW" },
{IR_LONG, 318, 0, "CB3_L1KVar" },
{IR_LONG, 320, 0, "CB3_L2KVar" },
{IR_LONG, 322, 0, "CB3_L3KVar" },
{IR_LONG, 324, 0, "CB3_L1KVA" },
{IR_LONG, 326, 0, "CB3_L2KVA" },
{IR_LONG, 328, 0, "CB3_L3KVA" },
{IR_LONG, 330, 0, "CB3_L1PF" },
{IR_LONG, 332, 0, "CB3_L2PF" },
{IR_LONG, 334, 0, "CB3_L3PF" },
{IR_LONG, 336, 0, "CB3_V1THD" },
{IR_LONG, 338, 0, "CB3_V2THD" },
{IR_LONG, 340, 0, "CB3_V3THD" },
{IR_LONG, 342, 0, "CB3_I1THD" },
{IR_LONG, 344, 0, "CB3_I2THD" },
{IR_LONG, 346, 0, "CB3_I3THD" },
{IR_LONG, 348, 0, "CB3_I1Kfactor" },
{IR_LONG, 350, 0, "CB3_I2Kfactor" },
{IR_LONG, 352, 0, "CB3_I3Kfactor" },
{IR_LONG, 354, 0, "CB3_I1TDD" },
{IR_LONG, 356, 0, "CB3_I2TDD" },
{IR_LONG, 358, 0, "CB3_I3TDD" },
{IR_LONG, 360, 0, "CB3_V12" },
{IR_LONG, 362, 0, "CB3_V23" },
{IR_LONG, 364, 0, "CB3_V31" },
{IR_LONG, 366, 0, "CB3_TotalKW" },
{IR_LONG, 368, 0, "CB3_TotalKVar" },
{IR_LONG, 370, 0, "CB3_TotalKVA" },
{IR_LONG, 372, 0, "CB3_TotalPF" },
{IR_LONG, 374, 0, "CB3_TotalPFLag" },
{IR_LONG, 376, 0, "CB3_TotalPFLead" },
{IR_LONG, 378, 0, "CB3_TotalKWImport" },
{IR_LONG, 380, 0, "CB3_TotalKWExport" },
{IR_LONG, 382, 0, "CB3_TotalKVarImport" },
{IR_LONG, 384, 0, "CB3_TotalKVarExport" },
{IR_LONG, 386, 0, "CB3_LN_Avg" },
{IR_LONG, 388, 0, "CB3_LL_Avg" },
{IR_LONG, 399, 0, "CB3_Status" },
// Circuit Breaker 4 (OB04)
{IR_LONG, 400, 0, "CB4_V1N" },
{IR_LONG, 402, 0, "CB4_V2N" },
{IR_LONG, 404, 0, "CB4_V3N" },
{IR_LONG, 406, 0, "CB4_I1" },
{IR_LONG, 408, 0, "CB4_I2" },
{IR_LONG, 410, 0, "CB4_I3" },
{IR_LONG, 412, 0, "CB4_L1KW" },
{IR_LONG, 414, 0, "CB4_L2KW" },
{IR_LONG, 416, 0, "CB4_L3KW" },
{IR_LONG, 418, 0, "CB4_L1KVar" },
{IR_LONG, 420, 0, "CB4_L2KVar" },
{IR_LONG, 422, 0, "CB4_L3KVar" },
{IR_LONG, 424, 0, "CB4_L1KVA" },
{IR_LONG, 426, 0, "CB4_L2KVA" },
{IR_LONG, 428, 0, "CB4_L3KVA" },
{IR_LONG, 430, 0, "CB4_L1PF" },
{IR_LONG, 432, 0, "CB4_L2PF" },
{IR_LONG, 434, 0, "CB4_L3PF" },
{IR_LONG, 436, 0, "CB4_V1THD" },
{IR_LONG, 438, 0, "CB4_V2THD" },
{IR_LONG, 440, 0, "CB4_V3THD" },
{IR_LONG, 442, 0, "CB4_I1THD" },
{IR_LONG, 444, 0, "CB4_I2THD" },
{IR_LONG, 446, 0, "CB4_I3THD" },
{IR_LONG, 448, 0, "CB4_I1Kfactor" },
{IR_LONG, 450, 0, "CB4_I2Kfactor" },
{IR_LONG, 452, 0, "CB4_I3Kfactor" },
{IR_LONG, 454, 0, "CB4_I1TDD" },
{IR_LONG, 456, 0, "CB4_I2TDD" },
{IR_LONG, 458, 0, "CB4_I3TDD" },
{IR_LONG, 460, 0, "CB4_V12" },
{IR_LONG, 462, 0, "CB4_V23" },
{IR_LONG, 464, 0, "CB4_V31" },
{IR_LONG, 466, 0, "CB4_TotalKW" },
{IR_LONG, 468, 0, "CB4_TotalKVar" },
{IR_LONG, 470, 0, "CB4_TotalKVA" },
{IR_LONG, 472, 0, "CB4_TotalPF" },
{IR_LONG, 474, 0, "CB4_TotalPFLag" },
{IR_LONG, 476, 0, "CB4_TotalPFLead" },
{IR_LONG, 478, 0, "CB4_TotalKWImport" },
{IR_LONG, 480, 0, "CB4_TotalKWExport" },
{IR_LONG, 482, 0, "CB4_TotalKVarImport" },
{IR_LONG, 484, 0, "CB4_TotalKVarExport" },
{IR_LONG, 486, 0, "CB4_LN_Avg" },
{IR_LONG, 488, 0, "CB4_LL_Avg" },
{IR_LONG, 499, 0, "CB4_Status" },
// Circuit Breaker 5 (OB05)
{IR_LONG, 500, 0, "CB5_V1N" },
{IR_LONG, 502, 0, "CB5_V2N" },
{IR_LONG, 504, 0, "CB5_V3N" },
{IR_LONG, 506, 0, "CB5_I1" },
{IR_LONG, 508, 0, "CB5_I2" },
{IR_LONG, 510, 0, "CB5_I3" },
{IR_LONG, 512, 0, "CB5_L1KW" },
{IR_LONG, 514, 0, "CB5_L2KW" },
{IR_LONG, 516, 0, "CB5_L3KW" },
{IR_LONG, 518, 0, "CB5_L1KVar" },
{IR_LONG, 520, 0, "CB5_L2KVar" },
{IR_LONG, 522, 0, "CB5_L3KVar" },
{IR_LONG, 524, 0, "CB5_L1KVA" },
{IR_LONG, 526, 0, "CB5_L2KVA" },
{IR_LONG, 528, 0, "CB5_L3KVA" },
{IR_LONG, 530, 0, "CB5_L1PF" },
{IR_LONG, 532, 0, "CB5_L2PF" },
{IR_LONG, 534, 0, "CB5_L3PF" },
{IR_LONG, 536, 0, "CB5_V1THD" },
{IR_LONG, 538, 0, "CB5_V2THD" },
{IR_LONG, 540, 0, "CB5_V3THD" },
{IR_LONG, 542, 0, "CB5_I1THD" },
{IR_LONG, 544, 0, "CB5_I2THD" },
{IR_LONG, 546, 0, "CB5_I3THD" },
{IR_LONG, 548, 0, "CB5_I1Kfactor" },
{IR_LONG, 550, 0, "CB5_I2Kfactor" },
{IR_LONG, 552, 0, "CB5_I3Kfactor" },
{IR_LONG, 554, 0, "CB5_I1TDD" },
{IR_LONG, 556, 0, "CB5_I2TDD" },
{IR_LONG, 558, 0, "CB5_I3TDD" },
{IR_LONG, 560, 0, "CB5_V12" },
{IR_LONG, 562, 0, "CB5_V23" },
{IR_LONG, 564, 0, "CB5_V31" },
{IR_LONG, 566, 0, "CB5_TotalKW" },
{IR_LONG, 568, 0, "CB5_TotalKVar" },
{IR_LONG, 570, 0, "CB5_TotalKVA" },
{IR_LONG, 572, 0, "CB5_TotalPF" },
{IR_LONG, 574, 0, "CB5_TotalPFLag" },
{IR_LONG, 576, 0, "CB5_TotalPFLead" },
{IR_LONG, 578, 0, "CB5_TotalKWImport" },
{IR_LONG, 580, 0, "CB5_TotalKWExport" },
{IR_LONG, 582, 0, "CB5_TotalKVarImport" },
{IR_LONG, 584, 0, "CB5_TotalKVarExport" },
{IR_LONG, 586, 0, "CB5_LN_Avg" },
{IR_LONG, 588, 0, "CB5_LL_Avg" },
{IR_LONG, 599, 0, "CB5_Status" },
// Circuit Breaker 6 (OB06)
{IR_LONG, 600, 0, "CB6_V1N" },
{IR_LONG, 602, 0, "CB6_V2N" },
{IR_LONG, 604, 0, "CB6_V3N" },
{IR_LONG, 606, 0, "CB6_I1" },
{IR_LONG, 608, 0, "CB6_I2" },
{IR_LONG, 610, 0, "CB6_I3" },
{IR_LONG, 612, 0, "CB6_L1KW" },
{IR_LONG, 614, 0, "CB6_L2KW" },
{IR_LONG, 616, 0, "CB6_L3KW" },
{IR_LONG, 618, 0, "CB6_L1KVar" },
{IR_LONG, 620, 0, "CB6_L2KVar" },
{IR_LONG, 622, 0, "CB6_L3KVar" },
{IR_LONG, 624, 0, "CB6_L1KVA" },
{IR_LONG, 626, 0, "CB6_L2KVA" },
{IR_LONG, 628, 0, "CB6_L3KVA" },
{IR_LONG, 630, 0, "CB6_L1PF" },
{IR_LONG, 632, 0, "CB6_L2PF" },
{IR_LONG, 634, 0, "CB6_L3PF" },
{IR_LONG, 636, 0, "CB6_V1THD" },
{IR_LONG, 638, 0, "CB6_V2THD" },
{IR_LONG, 640, 0, "CB6_V3THD" },
{IR_LONG, 642, 0, "CB6_I1THD" },
{IR_LONG, 644, 0, "CB6_I2THD" },
{IR_LONG, 646, 0, "CB6_I3THD" },
{IR_LONG, 648, 0, "CB6_I1Kfactor" },
{IR_LONG, 650, 0, "CB6_I2Kfactor" },
{IR_LONG, 652, 0, "CB6_I3Kfactor" },
{IR_LONG, 654, 0, "CB6_I1TDD" },
{IR_LONG, 656, 0, "CB6_I2TDD" },
{IR_LONG, 658, 0, "CB6_I3TDD" },
{IR_LONG, 660, 0, "CB6_V12" },
{IR_LONG, 662, 0, "CB6_V23" },
{IR_LONG, 664, 0, "CB6_V31" },
{IR_LONG, 666, 0, "CB6_TotalKW" },
{IR_LONG, 668, 0, "CB6_TotalKVar" },
{IR_LONG, 670, 0, "CB6_TotalKVA" },
{IR_LONG, 672, 0, "CB6_TotalPF" },
{IR_LONG, 674, 0, "CB6_TotalPFLag" },
{IR_LONG, 676, 0, "CB6_TotalPFLead" },
{IR_LONG, 678, 0, "CB6_TotalKWImport" },
{IR_LONG, 680, 0, "CB6_TotalKWExport" },
{IR_LONG, 682, 0, "CB6_TotalKVarImport" },
{IR_LONG, 684, 0, "CB6_TotalKVarExport" },
{IR_LONG, 686, 0, "CB6_LN_Avg" },
{IR_LONG, 688, 0, "CB6_LL_Avg" },
{IR_LONG, 699, 0, "CB6_Status" },
// Circuit Breaker 7 (OB07)
{IR_LONG, 700, 0, "CB7_V1N" },
{IR_LONG, 702, 0, "CB7_V2N" },
{IR_LONG, 704, 0, "CB7_V3N" },
{IR_LONG, 706, 0, "CB7_I1" },
{IR_LONG, 708, 0, "CB7_I2" },
{IR_LONG, 710, 0, "CB7_I3" },
{IR_LONG, 712, 0, "CB7_L1KW" },
{IR_LONG, 714, 0, "CB7_L2KW" },
{IR_LONG, 716, 0, "CB7_L3KW" },
{IR_LONG, 718, 0, "CB7_L1KVar" },
{IR_LONG, 720, 0, "CB7_L2KVar" },
{IR_LONG, 722, 0, "CB7_L3KVar" },
{IR_LONG, 724, 0, "CB7_L1KVA" },
{IR_LONG, 726, 0, "CB7_L2KVA" },
{IR_LONG, 728, 0, "CB7_L3KVA" },
{IR_LONG, 730, 0, "CB7_L1PF" },
{IR_LONG, 732, 0, "CB7_L2PF" },
{IR_LONG, 734, 0, "CB7_L3PF" },
{IR_LONG, 736, 0, "CB7_V1THD" },
{IR_LONG, 738, 0, "CB7_V2THD" },
{IR_LONG, 740, 0, "CB7_V3THD" },
{IR_LONG, 742, 0, "CB7_I1THD" },
{IR_LONG, 744, 0, "CB7_I2THD" },
{IR_LONG, 746, 0, "CB7_I3THD" },
{IR_LONG, 748, 0, "CB7_I1Kfactor" },
{IR_LONG, 750, 0, "CB7_I2Kfactor" },
{IR_LONG, 752, 0, "CB7_I3Kfactor" },
{IR_LONG, 754, 0, "CB7_I1TDD" },
{IR_LONG, 756, 0, "CB7_I2TDD" },
{IR_LONG, 758, 0, "CB7_I3TDD" },
{IR_LONG, 760, 0, "CB7_V12" },
{IR_LONG, 762, 0, "CB7_V23" },
{IR_LONG, 764, 0, "CB7_V31" },
{IR_LONG, 766, 0, "CB7_TotalKW" },
{IR_LONG, 768, 0, "CB7_TotalKVar" },
{IR_LONG, 770, 0, "CB7_TotalKVA" },
{IR_LONG, 772, 0, "CB7_TotalPF" },
{IR_LONG, 774, 0, "CB7_TotalPFLag" },
{IR_LONG, 776, 0, "CB7_TotalPFLead" },
{IR_LONG, 778, 0, "CB7_TotalKWImport" },
{IR_LONG, 780, 0, "CB7_TotalKWExport" },
{IR_LONG, 782, 0, "CB7_TotalKVarImport" },
{IR_LONG, 784, 0, "CB7_TotalKVarExport" },
{IR_LONG, 786, 0, "CB7_LN_Avg" },
{IR_LONG, 788, 0, "CB7_LL_Avg" },
{IR_LONG, 799, 0, "CB7_Status" },
// Circuit Breaker 8 (OB08)
{IR_LONG, 800, 0, "CB8_V1N" },
{IR_LONG, 802, 0, "CB8_V2N" },
{IR_LONG, 804, 0, "CB8_V3N" },
{IR_LONG, 806, 0, "CB8_I1" },
{IR_LONG, 808, 0, "CB8_I2" },
{IR_LONG, 810, 0, "CB8_I3" },
{IR_LONG, 812, 0, "CB8_L1KW" },
{IR_LONG, 814, 0, "CB8_L2KW" },
{IR_LONG, 816, 0, "CB8_L3KW" },
{IR_LONG, 818, 0, "CB8_L1KVar" },
{IR_LONG, 820, 0, "CB8_L2KVar" },
{IR_LONG, 822, 0, "CB8_L3KVar" },
{IR_LONG, 824, 0, "CB8_L1KVA" },
{IR_LONG, 826, 0, "CB8_L2KVA" },
{IR_LONG, 828, 0, "CB8_L3KVA" },
{IR_LONG, 830, 0, "CB8_L1PF" },
{IR_LONG, 832, 0, "CB8_L2PF" },
{IR_LONG, 834, 0, "CB8_L3PF" },
{IR_LONG, 836, 0, "CB8_V1THD" },
{IR_LONG, 838, 0, "CB8_V2THD" },
{IR_LONG, 840, 0, "CB8_V3THD" },
{IR_LONG, 842, 0, "CB8_I1THD" },
{IR_LONG, 844, 0, "CB8_I2THD" },
{IR_LONG, 846, 0, "CB8_I3THD" },
{IR_LONG, 848, 0, "CB8_I1Kfactor" },
{IR_LONG, 850, 0, "CB8_I2Kfactor" },
{IR_LONG, 852, 0, "CB8_I3Kfactor" },
{IR_LONG, 854, 0, "CB8_I1TDD" },
{IR_LONG, 856, 0, "CB8_I2TDD" },
{IR_LONG, 858, 0, "CB8_I3TDD" },
{IR_LONG, 860, 0, "CB8_V12" },
{IR_LONG, 862, 0, "CB8_V23" },
{IR_LONG, 864, 0, "CB8_V31" },
{IR_LONG, 866, 0, "CB8_TotalKW" },
{IR_LONG, 868, 0, "CB8_TotalKVar" },
{IR_LONG, 870, 0, "CB8_TotalKVA" },
{IR_LONG, 872, 0, "CB8_TotalPF" },
{IR_LONG, 874, 0, "CB8_TotalPFLag" },
{IR_LONG, 876, 0, "CB8_TotalPFLead" },
{IR_LONG, 878, 0, "CB8_TotalKWImport" },
{IR_LONG, 880, 0, "CB8_TotalKWExport" },
{IR_LONG, 882, 0, "CB8_TotalKVarImport" },
{IR_LONG, 884, 0, "CB8_TotalKVarExport" },
{IR_LONG, 886, 0, "CB8_LN_Avg" },
{IR_LONG, 888, 0, "CB8_LL_Avg" },
{IR_LONG, 899, 0, "CB8_Status" },
// Circuit Breaker 8 (OB08)
{IR_LONG, 900, 0, "CB9_V1N" },
{IR_LONG, 902, 0, "CB9_V2N" },
{IR_LONG, 904, 0, "CB9_V3N" },
{IR_LONG, 906, 0, "CB9_I1" },
{IR_LONG, 908, 0, "CB9_I2" },
{IR_LONG, 910, 0, "CB9_I3" },
{IR_LONG, 912, 0, "CB9_L1KW" },
{IR_LONG, 914, 0, "CB9_L2KW" },
{IR_LONG, 916, 0, "CB9_L3KW" },
{IR_LONG, 918, 0, "CB9_L1KVar" },
{IR_LONG, 920, 0, "CB9_L2KVar" },
{IR_LONG, 922, 0, "CB9_L3KVar" },
{IR_LONG, 924, 0, "CB9_L1KVA" },
{IR_LONG, 926, 0, "CB9_L2KVA" },
{IR_LONG, 928, 0, "CB9_L3KVA" },
{IR_LONG, 930, 0, "CB9_L1PF" },
{IR_LONG, 932, 0, "CB9_L2PF" },
{IR_LONG, 934, 0, "CB9_L3PF" },
{IR_LONG, 936, 0, "CB9_V1THD" },
{IR_LONG, 938, 0, "CB9_V2THD" },
{IR_LONG, 940, 0, "CB9_V3THD" },
{IR_LONG, 942, 0, "CB9_I1THD" },
{IR_LONG, 944, 0, "CB9_I2THD" },
{IR_LONG, 946, 0, "CB9_I3THD" },
{IR_LONG, 948, 0, "CB9_I1Kfactor" },
{IR_LONG, 950, 0, "CB9_I2Kfactor" },
{IR_LONG, 952, 0, "CB9_I3Kfactor" },
{IR_LONG, 954, 0, "CB9_I1TDD" },
{IR_LONG, 956, 0, "CB9_I2TDD" },
{IR_LONG, 958, 0, "CB9_I3TDD" },
{IR_LONG, 960, 0, "CB9_V12" },
{IR_LONG, 962, 0, "CB9_V23" },
{IR_LONG, 964, 0, "CB9_V31" },
{IR_LONG, 966, 0, "CB9_TotalKW" },
{IR_LONG, 968, 0, "CB9_TotalKVar" },
{IR_LONG, 970, 0, "CB9_TotalKVA" },
{IR_LONG, 972, 0, "CB9_TotalPF" },
{IR_LONG, 974, 0, "CB9_TotalPFLag" },
{IR_LONG, 976, 0, "CB9_TotalPFLead" },
{IR_LONG, 978, 0, "CB9_TotalKWImport" },
{IR_LONG, 980, 0, "CB9_TotalKWExport" },
{IR_LONG, 982, 0, "CB9_TotalKVarImport" },
{IR_LONG, 984, 0, "CB9_TotalKVarExport" },
{IR_LONG, 986, 0, "CB9_LN_Avg" },
{IR_LONG, 988, 0, "CB9_LL_Avg" },
{IR_LONG, 999, 0, "CB9_Status" },
{IR_FLOAT, 1068, 0, "Amps G" },
{IR_FLOAT, 1066, 0, "Amps N" },
{IR_FLOAT, 1087, 0, "kWh" },
{IR_FLOAT, 1091, 0, "PF" },
{IR, 1150, 0, "CB_Status" },
{IR, 1151, 0, "CB_Tripped" },
// Circuit Breaker 1 (CB1)
{IR_LONG, 106, 0, "CB1_I1" }, //0.01x
{IR_LONG, 108, 0, "CB1_I2" }, //0.01x
{IR_LONG, 110, 0, "CB1_I3" }, //0.01x
{IR_LONG, 170, 0, "CB1_kVA" }, //0.001x
{IR_LONG, 124, 0, "CB1_kVA1" }, //0.001x
{IR_LONG, 126, 0, "CB1_kVA2" }, //0.001x
{IR_LONG, 128, 0, "CB1_kVA3" }, //0.001x
{IR_LONG, 168, 0, "CB1_kVAR" }, //0.001x
{IR_LONG, 166, 0, "CB1_kW" }, //0.001x
{IR_LONG, 112, 0, "CB1_kW1" }, //0.001x
{IR_LONG, 114, 0, "CB1_kW2" }, //0.001x
{IR_LONG, 116, 0, "CB1_kW3" }, //0.001x
{IR_LONG, 1113, 0, "CB1_kWh" },
{IR_LONG, 172, 0, "CB1_PF" }, //0.001x
// Circuit Breaker 2 (CB1)
{IR_LONG, 206, 0, "CB2_I1" }, //0.01x
{IR_LONG, 208, 0, "CB2_I2" }, //0.01x
{IR_LONG, 210, 0, "CB2_I3" }, //0.01x
{IR_LONG, 270, 0, "CB2_kVA" }, //0.001x
{IR_LONG, 224, 0, "CB2_kVA1" }, //0.001x
{IR_LONG, 226, 0, "CB2_kVA2" }, //0.001x
{IR_LONG, 228, 0, "CB2_kVA3" }, //0.001x
{IR_LONG, 268, 0, "CB2_kVAR" }, //0.001x
{IR_LONG, 266, 0, "CB2_kW" }, //0.001x
{IR_LONG, 212, 0, "CB2_kW1" }, //0.001x
{IR_LONG, 214, 0, "CB2_kW2" }, //0.001x
{IR_LONG, 216, 0, "CB2_kW3" }, //0.001x
{IR_LONG, 1168, 0, "CB2_kWh" },
{IR_LONG, 272, 0, "CB2_PF" }, //0.001x
// Circuit Breaker 3 (CB1)
{IR_LONG, 306, 0, "CB3_I1" }, //0.01x
{IR_LONG, 308, 0, "CB3_I2" }, //0.01x
{IR_LONG, 310, 0, "CB3_I3" }, //0.01x
{IR_LONG, 370, 0, "CB3_kVA" }, //0.001x
{IR_LONG, 324, 0, "CB3_kVA1" }, //0.001x
{IR_LONG, 326, 0, "CB3_kVA2" }, //0.001x
{IR_LONG, 328, 0, "CB3_kVA3" }, //0.001x
{IR_LONG, 368, 0, "CB3_kVAR" }, //0.001x
{IR_LONG, 366, 0, "CB3_kW" }, //0.001x
{IR_LONG, 312, 0, "CB3_kW1" }, //0.001x
{IR_LONG, 314, 0, "CB3_kW2" }, //0.001x
{IR_LONG, 316, 0, "CB3_kW3" }, //0.001x
{IR_LONG, 1223, 0, "CB3_kWh" },
{IR_LONG, 372, 0, "CB3_PF" }, //0.001x
// Circuit Breaker 4 (CB1)
{IR_LONG, 406, 0, "CB4_I1" }, //0.01x
{IR_LONG, 408, 0, "CB4_I2" }, //0.01x
{IR_LONG, 410, 0, "CB4_I3" }, //0.01x
{IR_LONG, 470, 0, "CB4_kVA" }, //0.001x
{IR_LONG, 424, 0, "CB4_kVA1" }, //0.001x
{IR_LONG, 426, 0, "CB4_kVA2" }, //0.001x
{IR_LONG, 428, 0, "CB4_kVA3" }, //0.001x
{IR_LONG, 468, 0, "CB4_kVAR" }, //0.001x
{IR_LONG, 466, 0, "CB4_kW" }, //0.001x
{IR_LONG, 412, 0, "CB4_kW1" }, //0.001x
{IR_LONG, 414, 0, "CB4_kW2" }, //0.001x
{IR_LONG, 416, 0, "CB4_kW3" }, //0.001x
{IR_LONG, 1278, 0, "CB4_kWh" },
{IR_LONG, 472, 0, "CB4_PF" }, //0.001x
// Circuit Breaker 5 (CB1)
{IR_LONG, 506, 0, "CB5_I1" }, //0.01x
{IR_LONG, 508, 0, "CB5_I2" }, //0.01x
{IR_LONG, 510, 0, "CB5_I3" }, //0.01x
{IR_LONG, 570, 0, "CB5_kVA" }, //0.001x
{IR_LONG, 524, 0, "CB5_kVA1" }, //0.001x
{IR_LONG, 526, 0, "CB5_kVA2" }, //0.001x
{IR_LONG, 528, 0, "CB5_kVA3" }, //0.001x
{IR_LONG, 568, 0, "CB5_kVAR" }, //0.001x
{IR_LONG, 566, 0, "CB5_kW" }, //0.001x
{IR_LONG, 512, 0, "CB5_kW1" }, //0.001x
{IR_LONG, 514, 0, "CB5_kW2" }, //0.001x
{IR_LONG, 516, 0, "CB5_kW3" }, //0.001x
{IR_LONG, 1333, 0, "CB5_kWh" },
{IR_LONG, 572, 0, "CB5_PF" }, //0.001x
// Circuit Breaker 6 (CB1)
{IR_LONG, 606, 0, "CB6_I1" }, //0.01x
{IR_LONG, 608, 0, "CB6_I2" }, //0.01x
{IR_LONG, 610, 0, "CB6_I3" }, //0.01x
{IR_LONG, 670, 0, "CB6_kVA" }, //0.001x
{IR_LONG, 624, 0, "CB6_kVA1" }, //0.001x
{IR_LONG, 626, 0, "CB6_kVA2" }, //0.001x
{IR_LONG, 628, 0, "CB6_kVA3" }, //0.001x
{IR_LONG, 668, 0, "CB6_kVAR" }, //0.001x
{IR_LONG, 666, 0, "CB6_kW" }, //0.001x
{IR_LONG, 612, 0, "CB6_kW1" }, //0.001x
{IR_LONG, 614, 0, "CB6_kW2" }, //0.001x
{IR_LONG, 616, 0, "CB6_kW3" }, //0.001x
{IR_LONG, 1388, 0, "CB6_kWh" },
{IR_LONG, 672, 0, "CB6_PF" }, //0.001x
// Circuit Breaker 7 (CB1)
{IR_LONG, 706, 0, "CB7_I1" }, //0.01x
{IR_LONG, 708, 0, "CB7_I2" }, //0.01x
{IR_LONG, 710, 0, "CB7_I3" }, //0.01x
{IR_LONG, 770, 0, "CB7_kVA" }, //0.001x
{IR_LONG, 724, 0, "CB7_kVA1" }, //0.001x
{IR_LONG, 726, 0, "CB7_kVA2" }, //0.001x
{IR_LONG, 728, 0, "CB7_kVA3" }, //0.001x
{IR_LONG, 768, 0, "CB7_kVAR" }, //0.001x
{IR_LONG, 766, 0, "CB7_kW" }, //0.001x
{IR_LONG, 712, 0, "CB7_kW1" }, //0.001x
{IR_LONG, 714, 0, "CB7_kW2" }, //0.001x
{IR_LONG, 716, 0, "CB7_kW3" }, //0.001x
{IR_LONG, 1443, 0, "CB7_kWh" },
{IR_LONG, 772, 0, "CB7_PF" }, //0.001x
// Circuit Breaker 8 (CB1)
{IR_LONG, 806, 0, "CB8_I1" }, //0.01x
{IR_LONG, 808, 0, "CB8_I2" }, //0.01x
{IR_LONG, 810, 0, "CB8_I3" }, //0.01x
{IR_LONG, 870, 0, "CB8_kVA" }, //0.001x
{IR_LONG, 824, 0, "CB8_kVA1" }, //0.001x
{IR_LONG, 826, 0, "CB8_kVA2" }, //0.001x
{IR_LONG, 828, 0, "CB8_kVA3" }, //0.001x
{IR_LONG, 868, 0, "CB8_kVAR" }, //0.001x
{IR_LONG, 866, 0, "CB8_kW" }, //0.001x
{IR_LONG, 812, 0, "CB8_kW1" }, //0.001x
{IR_LONG, 814, 0, "CB8_kW2" }, //0.001x
{IR_LONG, 816, 0, "CB8_kW3" }, //0.001x
{IR_LONG, 1498, 0, "CB8_kWh" },
{IR_LONG, 872, 0, "CB8_PF" }, //0.001x
// PDU Output
{IR_LONG, 906, 0, "Output_I1" }, //0.01x
{IR_LONG, 908, 0, "Output_I2" },
{IR_LONG, 910, 0, "Output_I3" },
{IR_LONG, 1068, 0, "Output_IG" },
{IR_LONG, 1066, 0, "Output_IN" },
{IR_LONG, 924, 0, "Output_kVA1" }, //0.001
{IR_LONG, 926, 0, "Output_kVA2" },
{IR_LONG, 928, 0, "Output_kVA3" },
{IR_LONG, 968, 0, "Output_kVAR" }, //0.001
{IR_LONG, 912, 0, "Output_kW1" }, //0.001x
{IR_LONG, 914, 0, "Output_kW2" },
{IR_LONG, 916, 0, "Output_kW3" },
{IR_LONG, 1086, 0, "Output_kWh" },
{IR_LONG, 1091, 0, "Output_PF" }, //0.001
{IR_LONG, 960, 0, "Output_V_AB" },
{IR_LONG, 900, 0, "Output_V_AN" }, //0.01x
{IR_LONG, 962, 0, "Output_V_BC" },
{IR_LONG, 902, 0, "Output_V_BN" },
{IR_LONG, 964, 0, "Output_V_CA" },
{IR_LONG, 904, 0, "Output_V_CN" },
{IR, 1550, 0, "CB_Status" },
{IR, 1551, 0, "CB_Tripped" },
}; };
//Size of modbus map used in FOR cycles, automatically calculated. //Size of modbus map used in FOR cycles, automatically calculated.

View File

@@ -43,7 +43,7 @@ RunningState<ModbusIP>::RunningState() {
addStrategy("Volts CA", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Volts CA", new SingleValueStrategy(480.0F, 5.0f, 1000));
addStrategy("PF", new SingleValueStrategy(0.9f, 0.05f, 1000)); addStrategy("PF", new SingleValueStrategy(0.9f, 0.05f, 1000));
addStrategy("Frequency", new SingleValueStrategy(60.0f, 0.7f, 1000));
addStrategy("Amps A", new SingleValueStrategy(1.0f, 10.0f, 1000)); addStrategy("Amps A", new SingleValueStrategy(1.0f, 10.0f, 1000));
addStrategy("Amps B", new SingleValueStrategy(1.0f, 10.0f, 1000)); addStrategy("Amps B", new SingleValueStrategy(1.0f, 10.0f, 1000));
addStrategy("Amps C", new SingleValueStrategy(1.0f, 10.0f, 1000)); addStrategy("Amps C", new SingleValueStrategy(1.0f, 10.0f, 1000));

View File

@@ -87,6 +87,7 @@ void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
setPointValue(equipment, "Amps C", 0.0f); setPointValue(equipment, "Amps C", 0.0f);
setPointValue(equipment, "kW", 0.0f); setPointValue(equipment, "kW", 0.0f);
setPointValue(equipment, "kVA", 0.0f); setPointValue(equipment, "kVA", 0.0f);
setPointValue(equipment, "Frequency", 0.0f);
} }
/** /**

View File

@@ -23,8 +23,8 @@
#include <ModbusIP_ESP8266.h> #include <ModbusIP_ESP8266.h>
const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */ const char *ssid = "QTS_CDR_Arduino"; /**< @brief The SSID of the WiFi network. */
const char *password = "123abc456"; /**< @brief The password for the WiFi network. */ const char *password = "123abc456"; /**< @brief The password for the WiFi network. */
IPAddress local_IP(172, 17, 30, 241); /**< @brief The static IP address for the device. */ IPAddress local_IP(172, 17, 33, 174); /**< @brief The static IP address for the device. */
IPAddress gateway(172, 17, 30, 1); /**< @brief The gateway IP address. */ IPAddress gateway(172, 17, 33, 1); /**< @brief The gateway IP address. */
IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */ IPAddress subnet(255, 255, 255, 0); /**< @brief The subnet mask. */
ModbusIP mb; ModbusIP mb;

View File

@@ -40,31 +40,32 @@
*/ */
template<> template<>
BatteryState<ModbusIP>::BatteryState() { BatteryState<ModbusIP>::BatteryState() {
addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS Current Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase A", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output RMS Current Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase B", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output RMS Current Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase C", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("System Output Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000));
addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase A", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase B", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase C", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs A", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs B", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs C", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("Battery Time Remaining", new RampStrategy(0.0F, 0.3f, 1000)); addStrategy("Battery Time Remaining", new RampStrategy(0.0f, 3.0f, 1000));
addStrategy("Percentage Load", new RampStrategy(0.0f, 5.0f, 1000));
} }
/** /**
@@ -95,95 +96,123 @@ State<ModbusIP>* BatteryState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
case 4: case 4:
return new BypassState<ModbusIP>(); return new BypassState<ModbusIP>();
break; break;
default: default:
break; break;
} }
float rating = getPointValue(equipment, "Px Rating"); float Battery_time = getPointValue(equipment, "Battery Time Remaining");
float load = getPointValue(equipment, "Px Load"); float Bat_Percent = Battery_time /4.80f;
float real_load = rating * (load/100.f); float select = 1.0f;
if (Bat_Percent > 98.0f){
Strategy_Behavior* ramp_strat = nullptr; setPointValue(equipment, "UPS Battery Status2", 0.0f);
select = 1.0f;
}
if (Bat_Percent > 20.0f) {
setPointValue(equipment, "UPS Battery Status1", 2.0f);
setPointValue(equipment, "Battery Low", 0.0f);
select = 1.0f;
}
if (Bat_Percent <= 20.0f && Bat_Percent >= 5.0f){
setPointValue(equipment, "UPS Battery Status1", 3.0f);
setPointValue(equipment, "Battery Low", 1.0f);
select = 0.8f;
}
if (Bat_Percent < 5.0f){
setPointValue(equipment, "UPS Battery Status1", 4.0f);
select = 0.05f;
}
float rating = getPointValue(equipment, "Px Rating");
float load = getPointValue(equipment, "Px Load");
float real_load = (rating) * (load/100.0f);
Strategy_Behavior* ramp_strat = nullptr;
//Output strategies //Output strategies
float Out_Vab = getPointValue(equipment, "System Output RMS A-B"); float Out_Vab = getPointValue(equipment, "System Output RMS A-B");
ramp_strat = getStrategy("System Output RMS Current Phase A"); ramp_strat = getStrategy("System Output RMS Current Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vab); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load*select);
float Out_Vbc = getPointValue(equipment, "System Output RMS B-C"); float Out_Vbc = getPointValue(equipment, "System Output RMS B-C");
ramp_strat = getStrategy("System Output RMS Current Phase B"); ramp_strat = getStrategy("System Output RMS Current Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vbc); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load*select);
float Out_Vca = getPointValue(equipment, "System Output RMS C-A"); float Out_Vca = getPointValue(equipment, "System Output RMS C-A");
ramp_strat = getStrategy("System Output RMS Current Phase C"); ramp_strat = getStrategy("System Output RMS Current Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vca); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load*select);
float Out_Van = getPointValue(equipment, "System Output RMS A-N");
float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A");
float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A");
ramp_strat = getStrategy("System Output Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia);
ramp_strat = getStrategy("System Output Apparent Power Phs A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * Out_PFa);
float Out_Vbn = getPointValue(equipment, "System Output RMS B-N");
float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B");
float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B");
ramp_strat = getStrategy("System Output Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib);
ramp_strat = getStrategy("System Output Apparent Power Phs B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * Out_PFb);
float Out_Vcn = getPointValue(equipment, "System Output RMS C-N");
float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C");
float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C");
ramp_strat = getStrategy("System Output Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic);
ramp_strat = getStrategy("System Output Apparent Power Phs C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * Out_PFc);
float Out_Van = getPointValue(equipment, "System Output RMS A-N"); setPointValue(equipment, "System Output Power", (real_load * Out_Vab)/1000.0f);
float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A"); setPointValue(equipment, "System Output Apparent Power", (real_load* Out_Vab * 0.9f)/1000.0f);
float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A");
ramp_strat = getStrategy("System Output Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia);
ramp_strat = getStrategy("System Output Apparent Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * Out_PFa);
float Out_Vbn = getPointValue(equipment, "System Output RMS B-N");
float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B");
float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B");
ramp_strat = getStrategy("System Output Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib);
ramp_strat = getStrategy("System Output Apparent Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * Out_PFb);
float Out_Vcn = getPointValue(equipment, "System Output RMS C-N");
float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C");
float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C");
ramp_strat = getStrategy("System Output Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic);
ramp_strat = getStrategy("System Output Apparent Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * Out_PFc);
float Battery_time = getPointValue(equipment, "Battery Time Remaining");
float Bat_Percent = Battery_time /4.80f;
if (Bat_Percent > 98.0f){
setPointValue(equipment, "UPS Battery Status2", 0.0f);
}
if (Bat_Percent > 20.0f) {
setPointValue(equipment, "UPS Battery Status1", 2.0f);
setPointValue(equipment, "Battery Low", 0.0f);
}
if (Bat_Percent <= 20.0f && Bat_Percent >= 5.0f){
setPointValue(equipment, "UPS Battery Status1", 3.0f);
setPointValue(equipment, "Battery Low", 1.0f);
}
if (Bat_Percent < 5.0f){
setPointValue(equipment, "UPS Battery Status1", 4.0f);
}
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
/** /**
* @brief Logic to execute once when entering the Battery state. * @brief Logic to execute once when entering the Battery state.
* Sets the "Run Status" for all EC fans to 1 to indicate they are active. * Sets the "Run Status" for all EC fans to 1 to indicate they are active.
* @param equipment Pointer to the Equipment instance. * @param equipment Pointer to the Equipment instance.
*/ */
template<> template<>
void BatteryState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void BatteryState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Battery State..."); Serial.println("Enter Battery State...");
setPointValue(equipment, "System Input RMS A-B", 0.0f);
setPointValue(equipment, "System Input RMS B-C", 0.0f);
setPointValue(equipment, "System Input RMS C-A", 0.0f);
setPointValue(equipment, "System Input RMS A-N", 0.0f);
setPointValue(equipment, "System Input RMS B-N", 0.0f);
setPointValue(equipment, "System Input RMS C-N", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase A", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase B", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase C", 0.0f);
setPointValue(equipment, "System Input Frequency", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs A", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs B", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs C", 0.0f);
setPointValue(equipment, "System Input Power Phase A", 0.0f);
setPointValue(equipment, "System Input Power Phase B", 0.0f);
setPointValue(equipment, "System Input Power Phase C", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs A", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs B", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs C", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS A-B", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS B-C", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS A-B", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS C-A", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS B-C", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS A-N", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS C-A", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS B-N", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS A-N", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS C-N", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS B-N", 0.0f);
setPointValue(equipment, "Bypass Input Frequency", 0.0f); setPointValue(equipment, "Bypass Input Voltage RMS C-N", 0.0f);
setPointValue(equipment, "Bypass Power Phase A", 0.0f); setPointValue(equipment, "Bypass Input Frequency", 0.0f);
setPointValue(equipment, "Bypass Power Phase B", 0.0f); setPointValue(equipment, "Bypass Power Phase A", 0.0f);
setPointValue(equipment, "Bypass Power Phase C", 0.0f); setPointValue(equipment, "Bypass Power Phase B", 0.0f);
setPointValue(equipment, "Bypass Power Phase C", 0.0f);
setPointValue(equipment, "UPS Loading Status", 6.0f); setPointValue(equipment, "UPS Loading Status", 6.0f);
setPointValue(equipment, "UPS Battery Status2", 2.0f); setPointValue(equipment, "UPS Battery Status2", 2.0f);
// You could also update a Modbus register to show the "standby" state
// You could also update a Modbus register to show the "standby" state
} }

View File

@@ -42,72 +42,72 @@ template<>
BypassState<ModbusIP>::BypassState() { BypassState<ModbusIP>::BypassState() {
//Input System //Input System
addStrategy("System Input RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS Current Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase A", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input RMS Current Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase B", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input RMS Current Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase C", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("System Input Frequency", new SingleValueStrategy(60.0f, 2.0f, 1000));
addStrategy("System Input Power Factor Phs A", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Input Power Factor Phs A", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Input Power Factor Phs B", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Input Power Factor Phs B", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Input Power Factor Phs C", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Input Power Factor Phs C", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Input Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase C", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs C", new RampStrategy(0.0f, 50.0f, 1000));
//Bypass System //Bypass System
addStrategy("Bypass Input Voltage RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("Bypass Input Voltage RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("Bypass Input Voltage RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("Bypass Input Voltage RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("Bypass Input Voltage RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("Bypass Input Voltage RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("Bypass Input Voltage RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("Bypass Input Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("Bypass Input Frequency", new SingleValueStrategy(60.0f, 2.0f, 1000));
addStrategy("Bypass Input Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("Bypass Input Power Phase A", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("Bypass Input Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("Bypass Input Power Phase B", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("Bypass Input Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("Bypass Input Power Phase C", new RampStrategy(0.0f, 25.0f, 1000));
//Output System //Output System
addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS Current Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase A", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output RMS Current Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase B", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output RMS Current Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase C", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("System Output Frequency", new SingleValueStrategy(60.0f, 2.0f, 1000));
addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase C", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Apparent Power Phs C", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("Battery Time Remaining", new RampStrategy(480.0F, 0.3f, 1000)); addStrategy("Battery Time Remaining", new RampStrategy(480.0f, 0.3f, 1000));
addStrategy("DC Bus Voltage", new SingleValueStrategy(518.0F, 5.0f, 1000)); addStrategy("DC Bus Voltage", new SingleValueStrategy(518.0f, 5.0f, 1000));
} }
/** /**
@@ -143,85 +143,85 @@ State<ModbusIP>* BypassState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
} }
float rating = getPointValue(equipment, "Px Rating"); float rating = getPointValue(equipment, "Px Rating");
float load = getPointValue(equipment, "Px Load"); float load = getPointValue(equipment, "Px Load");
float real_load = rating * (load/100.f); float real_load = (rating) * (load/100.0f);
Strategy_Behavior* ramp_strat = nullptr; Strategy_Behavior* ramp_strat = nullptr;
//Input strategies //Input strategies
float In_Vab = getPointValue(equipment, "System Input RMS A-B"); float In_Vab = getPointValue(equipment, "System Input RMS A-B");
ramp_strat = getStrategy("System Input RMS Current Phase A"); ramp_strat = getStrategy("System Input RMS Current Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vab); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float In_Vbc = getPointValue(equipment, "System Input RMS B-C"); float In_Vbc = getPointValue(equipment, "System Input RMS B-C");
ramp_strat = getStrategy("System Input RMS Current Phase B"); ramp_strat = getStrategy("System Input RMS Current Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vbc); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float In_Vca = getPointValue(equipment, "System Input RMS C-A"); float In_Vca = getPointValue(equipment, "System Input RMS C-A");
ramp_strat = getStrategy("System Input RMS Current Phase C"); ramp_strat = getStrategy("System Input RMS Current Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vca); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float In_Van = getPointValue(equipment, "System Input RMS A-N"); float In_Van = getPointValue(equipment, "System Input RMS A-N");
float In_Ia = getPointValue(equipment, "System Input RMS Current Phase A"); float In_Ia = getPointValue(equipment, "System Input RMS Current Phase A");
float In_PFa = getPointValue(equipment, "System Input Power Factor Phs A"); float In_PFa = getPointValue(equipment, "System Input Power Factor Phs A");
ramp_strat = getStrategy("System Input Power Phase A"); ramp_strat = getStrategy("System Input Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia);
ramp_strat = getStrategy("Bypass Power Phase A"); ramp_strat = getStrategy("Bypass Input Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia);
ramp_strat = getStrategy("System Input Apparent Power Phase A"); ramp_strat = getStrategy("System Input Apparent Power Phs A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia * In_PFa); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia * 0.9f);
float In_Vbn = getPointValue(equipment, "System Input RMS B-N"); float In_Vbn = getPointValue(equipment, "System Input RMS B-N");
float In_Ib = getPointValue(equipment, "System Input RMS Current Phase B"); float In_Ib = getPointValue(equipment, "System Input RMS Current Phase B");
float In_PFb = getPointValue(equipment, "System Input Power Factor Phs B"); float In_PFb = getPointValue(equipment, "System Input Power Factor Phs B");
ramp_strat = getStrategy("System Input Power Phase B"); ramp_strat = getStrategy("System Input Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib);
ramp_strat = getStrategy("Bypass Power Phase B"); ramp_strat = getStrategy("Bypass Input Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib);
ramp_strat = getStrategy("System Input Apparent Power Phase B"); ramp_strat = getStrategy("System Input Apparent Power Phs B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib * In_PFb); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib * 0.9f);
float In_Vcn = getPointValue(equipment, "System Input RMS C-N"); float In_Vcn = getPointValue(equipment, "System Input RMS C-N");
float In_Ic = getPointValue(equipment, "System Input RMS Current Phase C"); float In_Ic = getPointValue(equipment, "System Input RMS Current Phase C");
float In_PFc = getPointValue(equipment, "System Input Power Factor Phs C"); float In_PFc = getPointValue(equipment, "System Input Power Factor Phs C");
ramp_strat = getStrategy("System Input Power Phase C"); ramp_strat = getStrategy("System Input Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic);
ramp_strat = getStrategy("Bypass Power Phase C"); ramp_strat = getStrategy("Bypass Input Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic);
ramp_strat = getStrategy("System Input Apparent Power Phase C"); ramp_strat = getStrategy("System Input Apparent Power Phs C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic * In_PFc); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic * 0.9f);
//Output strategies //Output strategies
float Out_Vab = getPointValue(equipment, "System Output RMS A-B"); float Out_Vab = getPointValue(equipment, "System Output RMS A-B");
ramp_strat = getStrategy("System Output RMS Current Phase A"); ramp_strat = getStrategy("System Output RMS Current Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vab); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Vbc = getPointValue(equipment, "System Output RMS B-C"); float Out_Vbc = getPointValue(equipment, "System Output RMS B-C");
ramp_strat = getStrategy("System Output RMS Current Phase B"); ramp_strat = getStrategy("System Output RMS Current Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vbc); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Vca = getPointValue(equipment, "System Output RMS C-A"); float Out_Vca = getPointValue(equipment, "System Output RMS C-A");
ramp_strat = getStrategy("System Output RMS Current Phase C"); ramp_strat = getStrategy("System Output RMS Current Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vca); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Van = getPointValue(equipment, "System Output RMS A-N"); float Out_Van = getPointValue(equipment, "System Output RMS A-N");
float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A"); float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A");
float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A"); float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A");
ramp_strat = getStrategy("System Output Power Phase A"); ramp_strat = getStrategy("System Output Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia);
ramp_strat = getStrategy("System Output Apparent Power Phase A"); ramp_strat = getStrategy("System Output Apparent Power Phs A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * Out_PFa); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * 0.9f);
float Out_Vbn = getPointValue(equipment, "System Output RMS B-N"); float Out_Vbn = getPointValue(equipment, "System Output RMS B-N");
float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B"); float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B");
float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B"); float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B");
ramp_strat = getStrategy("System Output Power Phase B"); ramp_strat = getStrategy("System Output Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib);
ramp_strat = getStrategy("System Output Apparent Power Phase B"); ramp_strat = getStrategy("System Output Apparent Power Phs B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * Out_PFb); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * 0.9f);
float Out_Vcn = getPointValue(equipment, "System Output RMS C-N"); float Out_Vcn = getPointValue(equipment, "System Output RMS C-N");
float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C"); float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C");
float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C"); float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C");
ramp_strat = getStrategy("System Output Power Phase C"); ramp_strat = getStrategy("System Output Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic);
ramp_strat = getStrategy("System Output Apparent Power Phase C"); ramp_strat = getStrategy("System Output Apparent Power Phs C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * Out_PFc); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * 0.9f);
float Battery_time = getPointValue(equipment, "Battery Time Remaining"); float Battery_time = getPointValue(equipment, "Battery Time Remaining");
float Bat_Percent = Battery_time /4.80f; float Bat_Percent = Battery_time /4.80f;
@@ -239,11 +239,12 @@ State<ModbusIP>* BypassState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
if (Bat_Percent < 5.0f){ if (Bat_Percent < 5.0f){
setPointValue(equipment, "UPS Battery Status1", 4.0f); setPointValue(equipment, "UPS Battery Status1", 4.0f);
} }
setPointValue(equipment, "System Output Power", (real_load * In_Vab)/1000.0f);
setPointValue(equipment, "System Output Apparent Power", (real_load* In_Vab * 0.9f)/1000.0f);
// Apply any strategies defined for the standby state // Apply any strategies defined for the standby state
_applyStrategies(equipment); _applyStrategies(equipment);
return nullptr; return nullptr;
} }
/** /**
* @brief Logic to execute once when entering the Bypass state. * @brief Logic to execute once when entering the Bypass state.
* Sets the "Run Status" for all EC fans to 1 to indicate they are active. * Sets the "Run Status" for all EC fans to 1 to indicate they are active.
@@ -252,9 +253,10 @@ State<ModbusIP>* BypassState<ModbusIP>::update(Equipment<ModbusIP>* equipment) {
template<> template<>
void BypassState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void BypassState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Battery State..."); Serial.println("Enter Bypass State...");
setPointValue(equipment, "UPS Loading Status", 4.0f); setPointValue(equipment, "UPS Loading Status", 4.0f);
setPointValue(equipment, "UPS Battery Status2", 3.0f); setPointValue(equipment, "UPS Battery Status2", 3.0f);
setPointValue(equipment, "Percentage Load", 0.0f);
// You could also update a Modbus register to show the "standby" state // You could also update a Modbus register to show the "standby" state
} }

View File

@@ -40,60 +40,60 @@
*/ */
template<> template<>
RunningState<ModbusIP>::RunningState() { RunningState<ModbusIP>::RunningState() {
addStrategy("System Input RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Input RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Input RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Input RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Input RMS Current Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase A", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input RMS Current Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase B", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input RMS Current Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input RMS Current Phase C", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Input Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("System Input Frequency", new SingleValueStrategy(60.0f, 2.0f, 1000));
addStrategy("System Input Power Factor Phs A", new SingleValueStrategy(93.0F, 0.5f, 1000)); addStrategy("System Input Power Factor Phs A", new SingleValueStrategy(93.0f, 0.5f, 1000));
addStrategy("System Input Power Factor Phs B", new SingleValueStrategy(93.0F, 0.5f, 1000)); addStrategy("System Input Power Factor Phs B", new SingleValueStrategy(93.0f, 0.5f, 1000));
addStrategy("System Input Power Factor Phs C", new SingleValueStrategy(93.0F, 0.5f, 1000)); addStrategy("System Input Power Factor Phs C", new SingleValueStrategy(93.0f, 0.5f, 1000));
addStrategy("System Input Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Power Phase C", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs A", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs B", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Input Apparent Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Input Apparent Power Phs C", new RampStrategy(0.0f, 50.0f, 1000));
addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS A-B", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS B-C", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0f, 5.0f, 1000));
addStrategy("System Output RMS C-A", new SingleValueStrategy(480.0F, 5.0f, 1000)); addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS A-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS B-N", new SingleValueStrategy(270.0F, 5.0f, 1000)); addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0f, 5.0f, 1000));
addStrategy("System Output RMS C-N", new SingleValueStrategy(270.0F, 5.0f, 1000));
addStrategy("System Output RMS Current Phase A", new RampStrategy(10.0F, 5.0f, 1000));
addStrategy("System Output RMS Current Phase B", new RampStrategy(10.0F, 5.0f, 1000));
addStrategy("System Output RMS Current Phase C", new RampStrategy(10.0F, 5.0f, 1000));
addStrategy("System Output Frequency", new SingleValueStrategy(60.0F, 2.0f, 1000)); addStrategy("System Output RMS Current Phase A", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output RMS Current Phase B", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output RMS Current Phase C", new RampStrategy(0.0f, 25.0f, 1000));
addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0F, 5.0f, 1000));
addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0F, 5.0f, 1000)); addStrategy("System Output Frequency", new SingleValueStrategy(60.0f, 2.0f, 1000));
addStrategy("System Output Power Phase A", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs A", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs B", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Factor Phs C", new SingleValueStrategy(93.0f, 5.0f, 1000));
addStrategy("System Output Apparent Power Phase A", new RampStrategy(10.0F, 5.0f, 1000));
addStrategy("System Output Apparent Power Phase B", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase A", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phase C", new RampStrategy(10.0F, 5.0f, 1000)); addStrategy("System Output Power Phase B", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Power Phase C", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("Battery Time Remaining", new RampStrategy(480.0F, 1.0f, 1000)); addStrategy("System Output Apparent Power Phs A", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phs B", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("System Output Apparent Power Phs C", new RampStrategy(10.0f, 50.0f, 1000));
addStrategy("DC Bus Voltage", new SingleValueStrategy(518.0F, 5.0f, 1000));
addStrategy("DC Bus Voltage", new SingleValueStrategy(518.0f, 5.0f, 1000));
addStrategy("Battery Time Remaining", new RampStrategy(480.0f, 1.0f, 1000));
addStrategy("Percentage Load", new RampStrategy(100.0f, 5.0f, 1000));
addStrategy("System Output Power", new SingleValueStrategy(0.0f, 5.0f, 1000));
addStrategy("System Output Apparent Power", new SingleValueStrategy(0.0f, 5.0f, 1000));
} }
/** /**
@@ -130,78 +130,81 @@ State<ModbusIP>* RunningState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
float rating = getPointValue(equipment, "Px Rating"); float rating = getPointValue(equipment, "Px Rating");
float load = getPointValue(equipment, "Px Load"); float load = getPointValue(equipment, "Px Load");
float real_load = (rating*1000.0f) * (load/100.f); float real_load = (rating) * (load/100.0f);
Strategy_Behavior* ramp_strat = nullptr; Strategy_Behavior* ramp_strat = nullptr;
//Input strategies //Input strategies
float In_Vab = getPointValue(equipment, "System Input RMS A-B"); float In_Vab = getPointValue(equipment, "System Input RMS A-B");
ramp_strat = getStrategy("System Input RMS Current Phase A"); ramp_strat = getStrategy("System Input RMS Current Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vab); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float In_Vbc = getPointValue(equipment, "System Input RMS B-C"); float In_Vbc = getPointValue(equipment, "System Input RMS B-C");
ramp_strat = getStrategy("System Input RMS Current Phase B"); ramp_strat = getStrategy("System Input RMS Current Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vbc); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float In_Vca = getPointValue(equipment, "System Input RMS C-A"); float In_Vca = getPointValue(equipment, "System Input RMS C-A");
ramp_strat = getStrategy("System Input RMS Current Phase C"); ramp_strat = getStrategy("System Input RMS Current Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/In_Vca); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
setPointValue(equipment, "System Output Power", (real_load * In_Vab)/1000.0f);
setPointValue(equipment, "System Output Apparent Power", (real_load* In_Vab * 0.9f)/1000.0f);
float In_Van = getPointValue(equipment, "System Input RMS A-N"); float In_Van = getPointValue(equipment, "System Input RMS A-N");
float In_Ia = getPointValue(equipment, "System Input RMS Current Phase A"); float In_Ia = getPointValue(equipment, "System Input RMS Current Phase A");
float In_PFa = getPointValue(equipment, "System Input Power Factor Phs A"); float In_PFa = getPointValue(equipment, "System Input Power Factor Phs A");
ramp_strat = getStrategy("System Input Power Phase A"); ramp_strat = getStrategy("System Input Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia);
ramp_strat = getStrategy("System Input Apparent Power Phase A"); ramp_strat = getStrategy("System Input Apparent Power Phs A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia * (In_PFa/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Van * In_Ia * 0.9f);
float In_Vbn = getPointValue(equipment, "System Input RMS B-N"); float In_Vbn = getPointValue(equipment, "System Input RMS B-N");
float In_Ib = getPointValue(equipment, "System Input RMS Current Phase B"); float In_Ib = getPointValue(equipment, "System Input RMS Current Phase B");
float In_PFb = getPointValue(equipment, "System Input Power Factor Phs B"); float In_PFb = getPointValue(equipment, "System Input Power Factor Phs B");
ramp_strat = getStrategy("System Input Power Phase B"); ramp_strat = getStrategy("System Input Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib);
ramp_strat = getStrategy("System Input Apparent Power Phase B"); ramp_strat = getStrategy("System Input Apparent Power Phs B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib * (In_PFb/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vbn * In_Ib * 0.9f);
float In_Vcn = getPointValue(equipment, "System Input RMS C-N"); float In_Vcn = getPointValue(equipment, "System Input RMS C-N");
float In_Ic = getPointValue(equipment, "System Input RMS Current Phase C"); float In_Ic = getPointValue(equipment, "System Input RMS Current Phase C");
float In_PFc = getPointValue(equipment, "System Input Power Factor Phs C"); float In_PFc = getPointValue(equipment, "System Input Power Factor Phs C");
ramp_strat = getStrategy("System Input Power Phase C"); ramp_strat = getStrategy("System Input Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic);
ramp_strat = getStrategy("System Input Apparent Power Phase C"); ramp_strat = getStrategy("System Input Apparent Power Phs C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic * (In_PFc/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(In_Vcn * In_Ic * 0.9f);
//Output strategies //Output strategies
float Out_Vab = getPointValue(equipment, "System Output RMS A-B"); float Out_Vab = getPointValue(equipment, "System Output RMS A-B");
ramp_strat = getStrategy("System Output RMS Current Phase A"); ramp_strat = getStrategy("System Output RMS Current Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vab); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Vbc = getPointValue(equipment, "System Output RMS B-C"); float Out_Vbc = getPointValue(equipment, "System Output RMS B-C");
ramp_strat = getStrategy("System Output RMS Current Phase B"); ramp_strat = getStrategy("System Output RMS Current Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vbc); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Vca = getPointValue(equipment, "System Output RMS C-A"); float Out_Vca = getPointValue(equipment, "System Output RMS C-A");
ramp_strat = getStrategy("System Output RMS Current Phase C"); ramp_strat = getStrategy("System Output RMS Current Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load/Out_Vca); static_cast<RampStrategy*>(ramp_strat)->setTarget(real_load);
float Out_Van = getPointValue(equipment, "System Output RMS A-N"); float Out_Van = getPointValue(equipment, "System Output RMS A-N");
float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A"); float Out_Ia = getPointValue(equipment, "System Output RMS Current Phase A");
float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A"); float Out_PFa = getPointValue(equipment, "System Output Power Factor Phs A");
ramp_strat = getStrategy("System Output Power Phase A"); ramp_strat = getStrategy("System Output Power Phase A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia);
ramp_strat = getStrategy("System Output Apparent Power Phase A"); ramp_strat = getStrategy("System Output Apparent Power Phs A");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * (Out_PFa/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Van * Out_Ia * 0.9f);
float Out_Vbn = getPointValue(equipment, "System Output RMS B-N"); float Out_Vbn = getPointValue(equipment, "System Output RMS B-N");
float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B"); float Out_Ib = getPointValue(equipment, "System Output RMS Current Phase B");
float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B"); float Out_PFb = getPointValue(equipment, "System Output Power Factor Phs B");
ramp_strat = getStrategy("System Output Power Phase B"); ramp_strat = getStrategy("System Output Power Phase B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib);
ramp_strat = getStrategy("System Output Apparent Power Phase B"); ramp_strat = getStrategy("System Output Apparent Power Phs B");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * (Out_PFb/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vbn * Out_Ib * 0.9f);
float Out_Vcn = getPointValue(equipment, "System Output RMS C-N"); float Out_Vcn = getPointValue(equipment, "System Output RMS C-N");
float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C"); float Out_Ic = getPointValue(equipment, "System Output RMS Current Phase C");
float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C"); float Out_PFc = getPointValue(equipment, "System Output Power Factor Phs C");
ramp_strat = getStrategy("System Output Power Phase C"); ramp_strat = getStrategy("System Output Power Phase C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic);
ramp_strat = getStrategy("System Output Apparent Power Phase C"); ramp_strat = getStrategy("System Output Apparent Power Phs C");
static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * (Out_PFc/100.0f)); static_cast<RampStrategy*>(ramp_strat)->setTarget(Out_Vcn * Out_Ic * 0.9f);
float Battery_time = getPointValue(equipment, "Battery Time Remaining"); float Battery_time = getPointValue(equipment, "Battery Time Remaining");
float Bat_Percent = Battery_time /4.80f; float Bat_Percent = Battery_time /4.80f;

View File

@@ -86,9 +86,60 @@ State<ModbusIP>* StandbyState<ModbusIP>::update(Equipment<ModbusIP>* equipment)
*/ */
template<> template<>
void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) { void StandbyState<ModbusIP>::enterState(Equipment<ModbusIP>* equipment) {
// Logic to run when the equipment enters this state // Logic to run when the equipment enters this state
Serial.println("Enter Standby State..."); Serial.println("Enter Standby State...");
setPointValue(equipment, "UPS Loading Status", 2.0f); setPointValue(equipment, "UPS Loading Status", 2.0f);
setPointValue(equipment, "System Input RMS A-B", 0.0f);
setPointValue(equipment, "System Input RMS B-C", 0.0f);
setPointValue(equipment, "System Input RMS C-A", 0.0f);
setPointValue(equipment, "System Input RMS A-N", 0.0f);
setPointValue(equipment, "System Input RMS B-N", 0.0f);
setPointValue(equipment, "System Input RMS C-N", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase A", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase B", 0.0f);
setPointValue(equipment, "System Input RMS Current Phase C", 0.0f);
setPointValue(equipment, "System Input Frequency", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs A", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs B", 0.0f);
setPointValue(equipment, "System Input Power Factor Phs C", 0.0f);
setPointValue(equipment, "System Input Power Phase A", 0.0f);
setPointValue(equipment, "System Input Power Phase B", 0.0f);
setPointValue(equipment, "System Input Power Phase C", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs A", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs B", 0.0f);
setPointValue(equipment, "System Input Apparent Power Phs C", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS A-B", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS B-C", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS C-A", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS A-N", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS B-N", 0.0f);
setPointValue(equipment, "Bypass Input Voltage RMS C-N", 0.0f);
setPointValue(equipment, "Bypass Input Frequency", 0.0f);
setPointValue(equipment, "Bypass Power Phase A", 0.0f);
setPointValue(equipment, "Bypass Power Phase B", 0.0f);
setPointValue(equipment, "Bypass Power Phase C", 0.0f);
setPointValue(equipment, "System Output RMS A-B", 0.0f);
setPointValue(equipment, "System Output RMS B-C", 0.0f);
setPointValue(equipment, "System Output RMS C-A", 0.0f);
setPointValue(equipment, "System Output RMS A-N", 0.0f);
setPointValue(equipment, "System Output RMS B-N", 0.0f);
setPointValue(equipment, "System Output RMS C-N", 0.0f);
setPointValue(equipment, "System Output RMS Current Phase A", 0.0f);
setPointValue(equipment, "System Output RMS Current Phase B", 0.0f);
setPointValue(equipment, "System Output RMS Current Phase C", 0.0f);
setPointValue(equipment, "System Output Frequency", 0.0f);
setPointValue(equipment, "System Output Power Factor Phs A", 0.0f);
setPointValue(equipment, "System Output Power Factor Phs B", 0.0f);
setPointValue(equipment, "System Output Power Factor Phs C", 0.0f);
setPointValue(equipment, "System Output Power Phase A", 0.0f);
setPointValue(equipment, "System Output Power Phase B", 0.0f);
setPointValue(equipment, "System Output Power Phase C", 0.0f);
setPointValue(equipment, "System Output Apparent Power Phs A", 0.0f);
setPointValue(equipment, "System Output Apparent Power Phs B", 0.0f);
setPointValue(equipment, "System Output Apparent Power Phs C", 0.0f);
setPointValue(equipment, "System Output Power", 0.0f);
setPointValue(equipment, "System Output Apparent Power", 0.0f);
} }
/** /**

View File

@@ -84,7 +84,7 @@ modbusMap mb_map[] =
{IR, 8, 0, "System Input RMS Current Phase B"}, {IR, 8, 0, "System Input RMS Current Phase B"},
{IR, 9, 0, "System Input RMS Current Phase C"}, {IR, 9, 0, "System Input RMS Current Phase C"},
{IR_10x, 10, 0, "System Input Frequency"}, {IR_10x, 10, 0, "System Input Frequency"},
{IR, 11, 0, "System Input Power Factor Phs A"}, {IR, 11, 0, "System Input Power Factor Phs A"}, //0.01
{IR, 12, 0, "System Input Power Factor Phs B"}, {IR, 12, 0, "System Input Power Factor Phs B"},
{IR, 13, 0, "System Input Power Factor Phs C"}, {IR, 13, 0, "System Input Power Factor Phs C"},
{IR_10x, 14, 0, "System Input Power Phase A"}, {IR_10x, 14, 0, "System Input Power Phase A"},
@@ -125,7 +125,8 @@ modbusMap mb_map[] =
{IR, 60, 0, "System Output Power"}, {IR, 60, 0, "System Output Power"},
{IR, 61, 0, "System Output Apparent Power"}, {IR, 61, 0, "System Output Apparent Power"},
{IR, 164, 0, "UPS Loading Status"}, {IR, 164, 0, "UPS Loading Status"},
{IR, 175, 0, "DC Bus Voltage"}, {IR, 175, 0, "DC Bus Voltage"},
{IR, 179, 0, "Percentage Load"},
{IR, 180, 0, "Battery Time Remaining"}, {IR, 180, 0, "Battery Time Remaining"},
{IR, 183, 0, "UPS Battery Status1"}, {IR, 183, 0, "UPS Battery Status1"},
{IR, 184, 0, "UPS Battery Status2"}, {IR, 184, 0, "UPS Battery Status2"},