Emmanuel HC 96f68f8d43 Breaker ABB Emax 2
Configuration of Breaker ABB Emax 2 Template
2025-11-14 11:24:55 -06:00
2025-11-14 11:24:55 -06:00
2025-11-14 11:24:55 -06:00
2025-09-21 17:58:42 -05:00

Industrial Equipment Emulator

This project is an Arduino-based emulator for an industrial equipment. It simulates the behavior of a real-world device (like a Computer Room Air Handler - CRAH) and communicates over Wi-Fi using the Modbus IP protocol.

The primary goal is to provide a flexible and extensible virtual device for testing, development, and training purposes without needing physical hardware.

Core Concepts for Automation Professionals

This software is built using a few key Object-Oriented Programming (OOP) concepts that make it powerful and easy to modify. If you think in terms of control systems, these concepts will feel very familiar.

1. The State Pattern: "What is the machine's current operating mode?"

In industrial automation, a machine has different operating modes: Standby, Running, Alarm/Fault, Manual Override, etc. The machine behaves differently in each mode.

The State Pattern organizes the code to mirror these real-world machine modes.

  • How it works here:

    • The Equipment class is our main "machine".
    • We have separate classes for each state: State_Standby, State_Running, State_Fail.
    • The Equipment object holds onto the current state object (e.g., an instance of State_Running).
    • The main loop() simply tells the current state object to update().
    • All the logic for the running mode is contained entirely within State_Running.cpp. All the logic for standby is in State_Standby.cpp.
  • Key Benefit: To change how the machine behaves in "Running" mode, you only need to modify the State_Running.cpp file. You don't have to touch any other part of the system. To add a new "Maintenance" mode, you just create a new State_Maintenance.cpp file. This is much safer and easier than editing a giant if/else block.

  • Files to see:

    • States/State.h: The "template" for all state classes.
    • States/State_Running.cpp: Defines all behavior when the unit is running.
    • States/State_Standby.cpp: Defines all behavior when the unit is in standby.
    • Equipment/Equipment.cpp: The main machine that changeState()s between different modes.

2. The Strategy Pattern: "How should this specific value behave?"

Within a single operating mode (like "Running"), different components might have different behaviors. For example, one fan's speed might be constant, another might ramp up and down, and a sensor reading might fluctuate randomly to simulate real-world conditions.

The Strategy Pattern lets us define these individual behaviors as interchangeable "algorithms" or "strategies".

  • Analogy: Think of a function block in a PLC. You might have a RAMP block, a PID block, or a SQUARE_WAVE_GENERATOR block. The Strategy Pattern lets us create these as software objects. We can then "assign" a behavior strategy to a specific Modbus point.

  • How it works here:

    • We have a family of "Strategy" classes: RampStrategy, SawStrategy, RandomStrategy, SquareStrategy, etc.
    • Inside a state file like State_Running.cpp, we assign these strategies to specific Modbus points. For example:
      // From State_Running.cpp
      // Assign a ramp behavior to Fan #5
      addStrategy("Speed EC Fan #5", new RampStrategy(100.0f, 1.5f, 2000));
      // Assign a random behavior to Fan #4
      addStrategy("Speed EC Fan #4", new RandomStrategy(1000));
      // Assign a sawtooth wave behavior to Fan #3
      addStrategy("Speed EC Fan #3", new SawStrategy(50.0f, 100.0f, 5.0f, 750));
      
  • Key Benefit: This makes the emulator incredibly dynamic. You can easily change the behavior of any point just by swapping out its strategy. Want Fan #4 to have a square wave pattern instead of random? Just change one line in State_Running.cpp. You don't have to rewrite any core logic.

  • Files to see:

    • Strategies/Strategy_Behavior.h: The "template" for all behavior strategies.
    • Strategies/Strategy_Ramp.h, Strategies/Strategy_Saw.h, etc.: The specific, reusable behavior algorithms.
    • States/State_Running.cpp: Where strategies are assigned to Modbus points for that state.

3. The Decorator Pattern: "How do we handle special data types?"

Modbus registers are fundamentally just 16-bit integers. However, in the real world, we use these integers to represent many different data types: booleans (coils), scaled integers (e.g., value * 10), 32-bit long integers, and 32-bit floating-point numbers.

The Decorator Pattern lets us "wrap" a basic Modbus point to add this extra functionality for handling data types without creating a whole new class for every possible combination.

  • Analogy: Think of a basic 4-20mA analog input card. That's your base object. Now, you add a "scaling block" in your PLC to convert the raw 4-20mA signal into a temperature in Celsius. That scaling block is a "Decorator". It doesn't change the input card, it just wraps its output to make it more useful.

  • How it works here:

    • We start with a basic Modbus_Point (like Modbus_Hreg for a Holding Register).
    • If a point needs to be treated as a float, we "decorate" or "wrap" it with a Modbus_FloatDecorator. This decorator knows how to take two 16-bit registers and combine them into a single 32-bit float value, and vice-versa.
    • If a point needs to be scaled, we can wrap it with a Modbus_ScaleDecorator.
  • Key Benefit: This keeps our code clean and avoids an explosion of classes. We don't need ModbusFloatHoldingRegister, ModbusScaledHoldingRegister, ModbusLongInputRegister, etc. We have our basic point types (Coil, Hreg, Ireg) and we simply "decorate" them with the data handling logic they need. This is all handled automatically by the Modbus_PointFactory.

  • Files to see:

    • Modbus_Points/Modbus_Point.h: The base for all points.
    • Modbus_Points/Modbus_PointDecorator.h: The base "wrapper" class.
    • Modbus_Points/Modbus_FloatDecorator.h: A specific wrapper that adds floating-point logic.
    • Modbus_Points/Modbus_PointFactory.cpp: The factory that automatically creates and decorates points based on the config.h map.

Project Structure

  • BaseEmulator.ino: The main entry point of the Arduino program. It handles Wi-Fi setup, initializes the Modbus server, and runs the main loop.
  • config.h: The central configuration file. This is where you define all the Modbus points for the device. You set the register type, address, and description here.
  • /Equipment: Contains the Equipment class, which represents the overall state machine.
  • /Modbus_Points: Contains the classes for different types of Modbus points (Modbus_Coil, Modbus_Hreg) and the Decorators (Modbus_FloatDecorator).
  • /States: Contains the different operating modes for the Equipment (e.g., State_Running).
  • /Strategies: Contains the reusable behavior algorithms for Modbus points (e.g., Strategy_Ramp).

How to Modify or Extend the Emulator

Use Equipment library

Look for the equipment type you want to use in the src folder, equipments are organized in BMS or EPMS type, there are subfolders for specify types.

  1. To add or change a Modbus point:

    • Open config.h.
    • Set Wifi parameters to communicate to the network.
    • Add a new line to the mb_map array, defining its category (e.g., HR_FLOAT), address, initial value, and a unique description.
  2. To change how a point behaves in the "Running" state:

    • Open States/State_Running.cpp.
    • In the RunningState() constructor, find or add an addStrategy() call for that point's description.
    • Assign it a new or different strategy (e.g., change new RandomStrategy(...) to new SingleValueStrategy(...)).
  3. To add a new operating mode (e.g., "Cleaning Cycle"):

    • Create new files: States/State_Cleaning.h and States/State_Cleaning.cpp.
    • Implement the logic for that mode, including adding strategies for how points should behave.
    • Update the state-switching logic (e.g., in State_Running.cpp or State_Standby.cpp) to allow transitioning into your new CleaningState.

Create a new Equipment type

  1. Copy the base

    • Copy one of the base folders in src, depending on the communication you need RTU or TCP, both configurations works with Firebeetle 2 ESP32.
  2. Save it into the correct folder

    • Save that folder into the correct type location.
    • Use a standar name, using this stucture Type_Manufacturer_Series_Protocol Example: VFD_ABB_ACH580_RTU
  3. Modify platformio.ini file

    • Copy a base configuration depending it's RTU or TCP
    • Paste it within the same file
    • Change the name of the configuration, preferrably using the same folder name
    • Add the folder to the configuration +<`folder_name'>

Description
ESP32 devices emulator
Readme 628 KiB
2026-07-08 21:34:13 +00:00
Languages
C++ 78.8%
C 21.2%