# CloudBatteryAttack Simulator ## NOTE, YOU NEED TO ADD DATA TO THE DATA FOLDER FOR THE SIMULATOR TO WORK. This simulator is the result of the following master's thesis: Cyberattack Evaluation of Cloud-controlled Energy Storage The simulator design can be seen in the Figure below. The modules and connections are described further down.  ## Modules of the simulator The simulator currently consists of 6 different modules: - Grid - Sensor - Network - Controller - Battery - GUI ### Grid The Grid module receives power (positive or negative) from the Battery module, and this power is added or subtracted from the internal produciton value, trying to match the consumption (that is read from a file with real-world data). The Grid gets a list of consumption values from one of the files located in **@/data/processed** which it uses to calculate the frequency. The frequency is calculated by a function located in the **lib** directory of the **src** folder. The calculated frequency is published to the Sensor module. ### Sensor The sensor gets the frequency from the Grid module by a subscription and forwards that frequency measurement over the Network module as a message (using endpoints). The sensor has an interval parameter specifying how often it should send the frequency measurement over the network. It is implemented as a counter for the number of packets reaching it. ### Network The Network module is probably the most complicated module in terms of communication. It has one endpoint for receiving messages and another for sending messages. Over these endpoints there is a filter for delaying packets and another filter for dropping packets. Just like a normal network, packets flow through the module and when packets flow they can be delayed, dropped, altered, replayed etc. This is where most of the cyberattacks occur (with the exception of Load Altering attacks). The Network module has two big pieces of logic, one for config messages and one for normal messages. Normal messages can also be recorded to stage a replay attack. ### Controller The Controller gets a frequency reading from the Sensor and inserts the measurement into a controller that generates a control signal. This signal is then sent to the Battery over the Network, indicating how much power should be pushed or pulled from the Grid. The control signal is currently produced by a PID controller but can easily be changed for any other algorithm that bases its output on the frequency error (current - nominal frequency). The Controller also receives status messages from the Battery every time it sends control signals. The status message currently consists of the battery's State of Charge. ### Battery The Battery base how much power to send to the Grid by the control signal received from the Controller. The power can be both positive (pushing power to the grid, i.e. discharging) and negative (pulling power from the grid, i.e. charging). ### GUI The GUI starts two threads, one for the graphical interface, and one for the HELICS simulation handling the communication of config messages with the rest of the simulator. The GUI defines everything that is visible on the screen and also the logic behind the attack script. # Installing the simulator To install the simulator, execute install.ps1 (Windows) or install.sh (Linux) (tested on Ubuntu server 22.04) # Running the simulator To run the simulator, execute run.ps1 (Windows) or run.sh (Linux). ## Configuration parameters The system has many parameters; they are given initial values via the *initial_parameters.json* file, but can also be changed by either the input fields in the **GUI** or via an external script called *attack.py*. Upon any changes, the updated JSON is broadcasted from the **GUI** module's main thread and is parsed by all other module instances to update their internal configuration. The parameters can currently be used to configure the Battery, Sensor, Grid, and the different Network instances. What the configuration parameters do and how they are used is explained below ### Grid parameters The Grid module defines five parameters: production_delay, consumption_scaling_factor, and three parameters part of the load_altering group. Load Altering (or LA) is a cyberattack where the grid power is altered by attacker-controlled devices (external to the simulator system). The parameters for simulating LA are: - offset (MW): a positive or negative bias added to the consumption power before being fed into the simulation - randomness (MW): at each time step, adds a random value from the uniform distribution ['-randomness', 'randomness'] to the consumption before it is fed into the simulation - interval: an integer that defines at what times the power is altered. An interval of 0 means no attack, an interval of 1 means altering occurs at every time-step, an interval of 2 means every other time-step, and so on. The production_delay parameter, if set to a non-zero value, causes the grid production to match the consumption data but with a delay of 'production_delay' seconds. This can be thought of as the large power plants slowly following the consumption curve but taking time to adapt. Finally, the consumption_scaling_factor is used to scale the consumption that is fed into the simulator (by default we are using the entire power consumption of Sweden in July 2023 so scaling it down with a factor < 1 into the size of a town's distribution grid could aid in making the simulation more realistic). ### Network parameters "sensor_to_controller_network": { "delay_min": 0.0, "delay_max": 0.0, "drop_rate": 0.0, "FDI": { "interval": 0, "offset": 0.0, "randomness": 0.0, "base": 0.0, "scaling_factor": 1.0 }, "replay" : { "amount": 0, "wait": 0 } }, The user can specify a uniform span of delays, packet drop rate, FDI attacks and replay attacks. The FDI paramters works in the following way: - Interval: 1 mean that every packet is modified, 2 means every other etc. - Offset: Adds or subtracts a constant value. - Randomness: Adds or subtracts a random value between [-randomness, +randomness]. - Base: Sends a constant value. - Scaling Factor: Scales the value with a constant. The Replay parameters works in the following way: - Amount: How many packets to record from the moment the update button is pressed (or when simulator starts if set in initial_parameters.json) - Wait: How many packets to wait before replaying after recording is finished. ### Other parameters "use_attack_script": false, "consumption_data_name": "consumption_20ms_short_cubic_average_window10_july_23", "battery": {"balancing_power": 2.0, "capacity": 2.0}, "sensor": {"interval": 50}, "pid_controller": {"kp": 2.0, "ki": 2.0, "kd": 0.0}, The other parameters works in the following way: - use_attack_script: Tells the simulator if it should use a user created script to modify simulator config parameters. - consumption_data_name: Where to fetch consumption data from (to the Grid module) - Battery.balancing_power: The maximum and minimum battery power. - Battery.capacity: Battery MWh. - Sensor.interval: How often the sensor should send frequency measurements to the Controller. - pid_Controller: The PID tunings. # HELICS The simulator is built using the co-simulation framework HELICS. It allows execution and coordination of multiple different "subsimulators" and handles the global time and communication between them so that they can interact. In our project, all of the "subsimulators" are small snippets of python code, but due to the nature of the HELICS framework they are relatively easy to replace with more sophisticated simulators. The documentation for HELICS is located at: https://docs.helics.org/en/latest/ And the github and examples which we drew inspiration from is located at: https://github.com/GMLC-TDC/HELICS-Examples Copyright (c) 2017-2019, Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable Energy, LLC. All rights reserved. The file *advanced_default_runner.json* is parsed by the HELICS broker for starting up the simulator (we use a single HELICS broker). This file defines how the modules are executed (as separate processes) and what HELICS configuration files are defined for each module (located in the **config** directory). The files in the **config** directory are parsed by each module process to configure time properties and inputs/outputs to other modules among other things (see HELICS documentation). In HELICS, module instances (so-called federates) can communicate in two ways: through endpoints (messages) or through values (publish, subscribe). HELICS messages are used to simulate packet-based communication (i.e. over a network), while HELICS values are used for continuous non-packetized connections (such as Power flow). The general execution flow of each module instance can be seen in the Figure. 