Skip to content
Snippets Groups Projects
Commit 4eac231e authored by Armin Co's avatar Armin Co
Browse files

Sample Opc Server

parent 09275c0e
No related branches found
No related tags found
No related merge requests found
cmake_minimum_required(VERSION 3.6) cmake_minimum_required(VERSION 3.6)
project(SmartGridModell) project(SmartGridModell)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 17)
add_compile_options(-Wall -Wextra -pedantic)
# Add spdlog for nice and easy logging # Add spdlog for nice and easy logging
add_subdirectory(libs/spdlog) add_subdirectory(libs/spdlog)
...@@ -30,6 +29,27 @@ add_executable(smart_grid.exe ...@@ -30,6 +29,27 @@ add_executable(smart_grid.exe
src/i2c/Node.cpp src/i2c/Node.cpp
src/com/Socket.cpp src/com/Socket.cpp
src/com/Protocol.cpp src/com/Protocol.cpp
src/ModelState.cpp
) )
target_link_libraries(smart_grid.exe spdlog) target_link_libraries(smart_grid.exe spdlog)
target_compile_options(smart_grid.exe PRIVATE -Wall -Wextra -pedantic)
# Add OPC UA
# macro(SET_OPTION option value)
# set(${option} ${value} CACHE "" INTERNAL FORCE)
# endmacro()
option(BUILD_CLIENT "Build Client" OFF)
option(BUILD_SERVER "Build Server" ON)
option(SSL_SUPPORT_MBEDTLS "Support rsa-oaep password encryption using mbedtls library " OFF)
option(BUILD_PYTHON "Build Python bindings" OFF)
option(BUILD_TESTING "Build and run tests" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
add_subdirectory(libs/freeopcua)
add_executable(opc_server.exe src/opc_server.cpp)
target_include_directories(opc_server.exe PUBLIC libs/freeopcua/include)
target_link_libraries(opc_server.exe opcuacore opcuaserver)
\ No newline at end of file
/// @file ModelState.cpp
///
#include "ModelState.hpp"
ModelState::ModelState(SmartGridModell &modell)
: m_modell(modell)
{
std::srand(std::time(nullptr));
}
void ModelState::update_wind()
{
double wind_by_sun = m_sun * 7.0 / 100.0; // wind by sun should by 5 max.
auto random_wind = ((std::rand() * 1.0) / RAND_MAX) * 5.0;
m_wind = power_wind[static_cast<int>(wind_by_sun + random_wind)];
}
void ModelState::update_modell()
{
auto sun = m_sun * 2.5;
auto wind = m_wind / 8.3;
auto renewable = (sun + wind) / 2;
m_modell.set_solar_plant(sun);
m_modell.update_windmill_speed(wind);
m_modell.set_windmill_net(wind);
m_modell.set_renewable_net(renewable);
if (m_production.conventional > 0)
{
m_modell.set_power_plant(200);
m_modell.set_village_color(200, renewable);
}
else
{
m_modell.set_power_plant(0);
m_modell.set_village_color(0, renewable);
}
}
void ModelState::update_power_production()
{
m_production.renewable.solar = m_sun * solar_size;
m_production.renewable.wind = m_wind * windpark_size;
if (m_usage.sum() > m_production.clean())
{
m_excess_power = 0.0;
m_production.conventional = m_usage.sum() - m_production.clean();
}
else
{
m_excess_power = m_production.clean() - m_usage.sum();
m_production.conventional = 0;
}
}
double ModelState::excess_power()
{
auto sum_prod = m_production.conventional + m_production.renewable.solar + m_production.renewable.wind;
auto sum_used = m_usage.industry + m_usage.village;
return sum_prod - sum_used;
}
void ModelState::update_power_consumption()
{
m_usage.village = village_consumption_at[m_time] * village_size;
if (m_producing == true)
{
m_usage.industry = MaxPower::industry;
}
else
{
m_usage.industry = 0.0;
}
}
void ModelState::update_time()
{
if (m_time < 23)
{
++m_time;
}
else
{
m_time = 0;
}
}
void ModelState::update_sun()
{
m_sun = sunnshine_percentage[m_time];
}
void ModelState::print_states()
{
spdlog::debug("Time <{}> Sun <{}> Wind<{}>", m_time, m_sun, m_wind);
spdlog::debug("Power Conv <{}> Solar <{}> Wind<{}>", m_production.conventional, m_production.renewable.solar, m_production.renewable.wind);
spdlog::debug("Usage Village<{}> Industry<{}>", m_usage.village, m_usage.industry);
spdlog::debug("excess_power<{}>", excess_power());
}
void ModelState::next_hour()
{
update_time();
update_sun();
update_wind();
update_power_consumption();
update_power_production();
update_modell();
print_states();
}
\ No newline at end of file
/// @file ModelState.hpp
///
#ifndef MODEL_STATE_HPP
#define MODEL_STATE_HPP
#include <cstdlib>
#include <ctime>
#include "spdlog/spdlog.h"
#include "SmartGridModell.hpp"
struct MaxPower
{
static constexpr double village = 600;
static constexpr double industry = 200;
static constexpr double wind = 250;
static constexpr double solar = 110;
};
constexpr double village_consumption_at[]{
98, 95, 93, 94, 95, 101, 115,
127, 132, 134, 136, 139, 138,
136, 134, 132, 130, 132, 132,
131, 125, 119, 114, 105, 98};
constexpr double sunnshine_percentage[]{
0, 0, 0, 0, 0, 0, 3,
12, 30, 52, 73, 88, 97,
100, 98, 91, 81, 66, 46,
25, 10, 2, 0, 0, 0};
constexpr double power_wind[]{
0, 3, 25, 82, 174,
321, 532, 815, 1180,
1612, 1890, 2000, 2100};
struct CleanPower
{
double solar = 0.0;
double wind = 0.0;
};
struct PowerProduction
{
double conventional;
CleanPower renewable;
double clean() { return renewable.solar + renewable.wind; }
double sum() { return conventional + clean(); }
};
struct PowerUsage
{
double village = 0.0;
double industry = 0.0;
double sum() { return village + industry; }
};
class ModelState
{
public:
ModelState(SmartGridModell &modell);
void next_hour();
double excess_power();
private:
void update_time();
void update_sun();
void update_wind();
void update_power_consumption();
void update_power_production();
void update_modell();
void print_states();
static constexpr double solar_size{10};
static constexpr double windpark_size{1.0};
static constexpr double village_size{10};
int m_time{0};
double m_sun{0};
double m_wind{0};
double m_excess_power{0.0};
PowerProduction m_production;
PowerUsage m_usage;
bool m_producing{false};
SmartGridModell &m_modell;
};
#endif
\ No newline at end of file
...@@ -12,6 +12,11 @@ SmartGridModell::SmartGridModell(i2c::Node& node, DefaultState initial_state) ...@@ -12,6 +12,11 @@ SmartGridModell::SmartGridModell(i2c::Node& node, DefaultState initial_state)
put_modell_into_state(initial_state); put_modell_into_state(initial_state);
} }
SmartGridModell::~SmartGridModell()
{
put_modell_into_state(DefaultState::Off);
}
void SmartGridModell::put_modell_into_state(DefaultState state) void SmartGridModell::put_modell_into_state(DefaultState state)
{ {
......
...@@ -58,6 +58,9 @@ public: ...@@ -58,6 +58,9 @@ public:
/// ///
SmartGridModell(i2c::Node& node, DefaultState initial_state = DefaultState::Off); SmartGridModell(i2c::Node& node, DefaultState initial_state = DefaultState::Off);
~SmartGridModell();
/// @brief Put the to one of the predefined states. /// @brief Put the to one of the predefined states.
/// ///
/// @param state Default state to which the modell will be changed. /// @param state Default state to which the modell will be changed.
......
...@@ -10,10 +10,8 @@ ...@@ -10,10 +10,8 @@
using namespace i2c; using namespace i2c;
Node::Node(uint8_t node_address) Node::Node(uint8_t node_address)
: m_address{node_address} : m_address{node_address}, m_device{-1}
, m_device{-1}
{ {
} }
Node::~Node() Node::~Node()
...@@ -39,8 +37,6 @@ bool Node::open_device(const char* i2c_device_name) ...@@ -39,8 +37,6 @@ bool Node::open_device(const char* i2c_device_name)
return true; return true;
} }
bool Node::send(uint8_t *data, ssize_t size) bool Node::send(uint8_t *data, ssize_t size)
{ {
ssize_t bytes_written = write(m_device, data, size); ssize_t bytes_written = write(m_device, data, size);
...@@ -68,7 +64,6 @@ bool Node::send(uint8_t reg, uint8_t val) ...@@ -68,7 +64,6 @@ bool Node::send(uint8_t reg, uint8_t val)
return send(data, 2); return send(data, 2);
} }
constexpr uint8_t i2c_smbus_max_block_size = 32; constexpr uint8_t i2c_smbus_max_block_size = 32;
struct i2c_data struct i2c_data
{ {
......
/// @file opc_server.cpp
///
#include <opc/ua/node.h>
#include <opc/ua/server/server.h>
using namespace OpcUa;
std::vector<OpcUa::Variant> my_method(NodeId context, std::vector<OpcUa::Variant> arguments)
{
std::cout << "Method triggered" << std::endl;
std::vector<OpcUa::Variant> result;
result.push_back(Variant(static_cast<uint8_t>(0)));
return result;
}
void add_nodes_to(uint32_t idx, Node &objects)
{
Node smart_grid = objects.AddFolder(idx, "smart_grid");
Node renewable = smart_grid.AddVariable(idx, "renewable_power", Variant(42.0));
Node prop = smart_grid.AddProperty(idx, "a_property_thin", Variant("something"));
Node method = smart_grid.AddMethod(idx, "trigger_method_x", my_method);
}
int main(int argc, char **argv)
{
auto logger = spdlog::stderr_color_mt("server");
OpcUa::UaServer server(logger);
server.SetEndpoint("opc.tcp://localhost:4840/opcua/smartgridserver");
server.SetServerURI("Smart Grid OPC UA Server");
server.Start();
auto idx = server.RegisterNamespace("smart-grid");
Node objects = server.GetObjectsNode();
add_nodes_to(idx, objects);
while (true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment