Merge branch 'develop' into rdavis/HUM_DriSteem_RTS_RX36_TCP

This commit is contained in:
Emmanuel HC
2025-11-04 08:25:51 -06:00
committed by GitHub
39 changed files with 1402 additions and 1302 deletions

View File

@@ -1,16 +1,12 @@
# CHILLER YORK YVAA 0428IOK46BAVTXX TCP
## Brief Introduction
*** NOTE! ***
This code has not been verified with Chiller and Chiller Manager PLC program.
It is a best-guess based on a preliminary review of Chiller PLC program, but
has yet to be fully vetted and local tested with PLC programs.
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
Chiller receives Chiller Temp SP and Enable from PLC. The Supply Temp will ramp to Chiller Temp SP in Run Mode.
Alarms are also simulated via Modscan, though those signals will be internal to Chiller.
Hard IO points simulated with Modscan: Sys 1 Alarm, Sys 2 Alarm.
Chiller Status is sent back to PLC.
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.
## List of Equipment
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
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.
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.
### Standby State
* **Chiller Status**: set to 0
* **Operational Code**: set to 77
* **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
* **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
* **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
*
* 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.
*
*/
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>* Sys2FanAlarmCommand = equipment->getModbus_Point("Sys 2 Fan Fault ON");
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);
}
// 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>* FreeCoolingMode = equipment->getModbus_Point("Free Cooling Mode");
Modbus_Point<ModbusRTU>* FreeCoolingValve = equipment->getModbus_Point("Free Cooling Valve");
if (FreeCoolingCommand->getValue() == 1) {
FreeCoolingMode->setValue(1);
FreeCoolingValve->setValue(1);
}
else {
FreeCoolingMode->setValue(0);
FreeCoolingValve->setValue(0);
}
FreeCoolingMode->setValue(FreeCoolingCommand->getValue());
FreeCoolingValve->setValue(FreeCoolingCommand->getValue());
}

View File

@@ -6,6 +6,7 @@
*
* This file contains the implementation for the FailState, which defines
* 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 "Equipment/Equipment.h"
@@ -29,15 +30,31 @@
* @brief Constructs a new FailState object.
*
* 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
* description of a Modbus point to be set as an active alarm.
* @param activeFaults A vector of strings, where each string is the
* description of the currently active faults.
*/
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 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 2 Fan 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.
*
* This method first updates all alarms states and Free Cooling Mode (for ease of testing).
* If all alarms have been cleared --> StandbyState.
* If alarms are still active, ensures the Chiller Start Command remains at 0.
* If all faults have been cleared --> StandbyState.
* If faults are still active, ensures the Chiller Start Command remains at 0.
*
* @param equipment Pointer to the Equipment instance.
* @return A pointer to a new State if a transition should occur, otherwise nullptr.
*/
template<>
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);
updateFreeCooling(equipment);
const std::vector<std::string> alarmDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm",
const std::vector<std::string> FaultDescriptions = {
"Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm",
};
// If no alarms active --> send to StandbyState()
bool alarms_active = false;
for (const auto& desc : alarmDescriptions) {
// If no faults active --> send to StandbyState()
bool faults_active = false;
for (const auto& desc : FaultDescriptions) {
Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc);
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);
// 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);
return nullptr;

View File

@@ -60,11 +60,11 @@ RunningState<ModbusRTU>::RunningState() {
addStrategy("Sys 1 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("VSD Output Frequency", new SingleValueStrategy(59.0f, 1.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 1 Compressor KW", new SingleValueStrategy(304.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);
updateFreeCooling(equipment);
std::vector<std::string> activeAlarmsDescriptions = {};
const std::vector<std::string> alarmDescriptions = {
"Sys 1 Alarm", "Sys 2 Alarm", "Sys 1 Fan Fault Alarm", "Sys 2 Fan Fault Alarm",
std::vector<std::string> activeFaultDescriptions = {};
const std::vector<std::string> FaultDescriptions = {
"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
bool alarms_active = false;
for (const auto& desc : alarmDescriptions) {
// Loop through faults, create array of active faults and send to FailState if any faults are active
bool faults_active = false;
for (const auto& desc : FaultDescriptions) {
Modbus_Point<ModbusRTU>* point = equipment->getModbus_Point(desc);
if (point->getValue() == 1) {
activeAlarmsDescriptions.push_back(desc);
alarms_active = true;
activeFaultDescriptions.push_back(desc);
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
if (Chiller_Enable == 0){
return new StandbyState<ModbusRTU>();
@@ -124,6 +124,17 @@ State<ModbusRTU>* RunningState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
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
_applyStrategies(equipment);
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 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 2 Fan 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 = {};
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
@@ -102,6 +103,17 @@ State<ModbusRTU>* StandbyState<ModbusRTU>::update(Equipment<ModbusRTU>* equipmen
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
_applyStrategies(equipment);
return nullptr;

View File

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

View File

@@ -1,11 +1,11 @@
/**
* @file main.cpp
* @brief Main execution program for the Daikin Chiller (RTU) Emulator.
* @author Emmanuel Hernandez Cruz
* @brief Main execution program for the York YVAA Chiller (RTU) 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 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.
*
* The setup() function initializes the following:

View File

@@ -38,16 +38,26 @@
*/
template<>
RunningState<ModbusIP>::RunningState() {
addStrategy("CW Valve Position", new PIDStrategy("RAT Setpoint", 1000, "RAT"));
addStrategy("Operating Hours EC Fan #1", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #2", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #3", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #4", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #5", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #6", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #7", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #8", new TotalizerStrategy(10000));
addStrategy("Operating Hours EC Fan #9", new TotalizerStrategy(10000));
addStrategy("CW Valve Position", new PIDStrategy("SAT Setpoint", 2000, "SAT Reading"));
addStrategy("SAT Reading", new SingleValueStrategy(0.0f, 3.0f, 1000));
addStrategy("Speed EC Fan #1", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #2", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #3", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #4", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #5", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #6", new RampStrategy(0.0f, 500.0f, 1000));
addStrategy("Speed EC Fan #7", new RampStrategy(0.0f, 500.0f, 1000));
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>();
}
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
_applyStrategies(equipment);
return nullptr;

View File

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