Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(iso15118_chargepoint)
add_subdirectory(iso15118_centralsystem)
add_subdirectory(quick_start_centralsystem)
add_subdirectory(quick_start_chargepoint)
add_subdirectory(quick_start_cs_lc_hybrid)
add_subdirectory(quick_start_localcontroller)
add_subdirectory(remote_chargepoint)
add_subdirectory(security_centralsystem)
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following examples are available for OCPP 1.6 standard :
* [Quick start Central System example](./quick_start_centralsystem/README.md)
* [Quick start Charge Point example](./quick_start_chargepoint/README.md)
* [Quick start Local Controller example](./quick_start_localcontroller/README.md)
* [Quick start Hybrid Central System / Local Controller example](./quick_start_cs_lc_hybrid/README.md)
* [Remote Charge Point example](./remote_chargepoint/README.md)

The following examples are available for OCPP 1.6 security extensions :
Expand Down
2 changes: 1 addition & 1 deletion examples/common/DefaultCentralSystemEventsHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ class DefaultCentralSystemEventsHandler : public ocpp::centralsystem::ICentralSy
/** @brief Remove a charge point from the connected charge points */
void removeChargePoint(const std::string& identifier);

private:
protected:
/** @brief Path to the V2G root CA */
std::filesystem::path m_iso_v2g_root_ca;
/** @brief Path to the MO root CA */
Expand Down
24 changes: 21 additions & 3 deletions examples/common/DefaultChargePointEventsHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,28 @@ bool DefaultChargePointEventsHandler::getMeterValue(
/** @copydoc bool IChargePointEventsHandler::remoteStartTransactionRequested(unsigned int, const std::string&) */
bool DefaultChargePointEventsHandler::remoteStartTransactionRequested(unsigned int connector_id, const std::string& id_tag)
{
bool ret = false;
cout << "Remote start transaction : " << connector_id << " - " << id_tag << endl;
m_remote_start_pending[connector_id - 1u] = true;
m_remote_start_id_tag[connector_id - 1u] = id_tag;
return true;
if (connector_id != 0)
{
m_remote_start_pending[connector_id - 1u] = true;
m_remote_start_id_tag[connector_id - 1u] = id_tag;
ret = true;
}
else
{
for (size_t i = 1; i <= m_config.ocppConfig().numberOfConnectors(); i++)
{
if (m_chargepoint->getConnectorStatus(i) < ChargePointStatus::Charging)
{
m_remote_start_pending[i - 1u] = true;
m_remote_start_id_tag[i - 1u] = id_tag;
ret = true;
break;
}
}
}
return ret;
}

/** @copydoc bool IChargePointEventsHandler::remoteStopTransactionRequested(unsigned int) */
Expand Down
13 changes: 13 additions & 0 deletions examples/common/config/LocalControllerConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ class LocalControllerConfig : public ocpp::config::ILocalControllerConfig
/** @brief Disconnect from Charge Point on Central System disconnection */
bool disconnectFromCpWhenCsDisconnected() const override { return getBool("DisconnectFromCpWhenCsDisconnected"); }

// Unused from Central System configuration interface

/** @brief Boot notification retry interval */
std::chrono::seconds bootNotificationRetryInterval() const override
{
return get<std::chrono::seconds>("BootNotificationRetryInterval");
}
/** @brief Heartbeat interval */
std::chrono::seconds heartbeatInterval() const override { return get<std::chrono::seconds>("HeartbeatInterval"); }
/** @brief If this variable set to true, then the Central System supports ISO 15118 plug and charge messages via the DataTransfer mechanism as
described in this application note. */
bool iso15118PnCEnabled() const override { return getBool("Iso15118PnCEnabled"); }

private:
/** @brief Configuration file */
ocpp::helpers::IniFile& m_config;
Expand Down
25 changes: 25 additions & 0 deletions examples/quick_start_cs_lc_hybrid/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
######################################################
# Quick start local controller example project #
######################################################

# Executable target
add_executable(quick_start_cs_lc_hybrid
main.cpp
HybridCentralSystemEventsHandler.cpp
)

# Additionnal libraries path
target_link_directories(quick_start_cs_lc_hybrid PRIVATE ${BIN_DIR})

# Dependencies
target_link_libraries(quick_start_cs_lc_hybrid
examples_common
localcontroller
)


# Copy to binary directory
ADD_CUSTOM_COMMAND(TARGET quick_start_cs_lc_hybrid
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/config/quick_start_cs_lc_hybrid.ini ${BIN_DIR}/
)
153 changes: 153 additions & 0 deletions examples/quick_start_cs_lc_hybrid/HybridCentralSystemEventsHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
MIT License

Copyright (c) 2020 Cedric Jimenez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include "HybridCentralSystemEventsHandler.h"
#include "StringHelpers.h"

#include <iostream>
#include <thread>

using namespace std;

/** @brief Constructor */
HybridCentralSystemEventsHandler::HybridCentralSystemEventsHandler(LocalControllerConfig& config,
std::filesystem::path iso_v2g_root_ca,
std::filesystem::path iso_mo_root_ca,
bool set_pending_status)
: DefaultCentralSystemEventsHandler(iso_v2g_root_ca, iso_mo_root_ca, set_pending_status), m_config(config)
{
}

/** @brief Destructor */
HybridCentralSystemEventsHandler::~HybridCentralSystemEventsHandler() { }

// ICentralSystemEventsHandler interface

/** @copydoc bool ICentralSystemEventsHandler::chargePointConnected(std::shared_ptr<ICentralSystem::IChargePoint>) */
void HybridCentralSystemEventsHandler::chargePointConnected(std::shared_ptr<ocpp::centralsystem::ICentralSystem::IChargePoint> chargepoint)
{
cout << "Charge point [" << chargepoint->identifier() << "] connected" << endl;
auto iter_chargepoint = m_chargepoints.find(chargepoint->identifier());
if (iter_chargepoint == m_chargepoints.end())
{
auto iter_forwarded = m_fowarded_chargepoints.find(chargepoint->identifier());
if (iter_forwarded == m_fowarded_chargepoints.end())
{
// Charge point ended with "lc" are forwared to Central System
if (ocpp::helpers::endsWith(chargepoint->identifier(), "lc"))
{
// Create Local Controller proxy
auto proxy = ocpp::localcontroller::IChargePointProxy::createFrom(chargepoint, m_config);

// Open connection to the Central System
ocpp::websockets::IWebsocketClient::Credentials credentials;
credentials.accept_untrusted_certificates = false;
credentials.allow_expired_certificates = false;
credentials.allow_selfsigned_certificates = false;
credentials.skip_server_name_check = false;
credentials.encoded_pem_certificates = false;
credentials.tls12_cipher_list = m_config.tlsv12CipherList();
credentials.tls13_cipher_list = m_config.tlsv13CipherList();
credentials.server_certificate_ca = m_config.tlsServerCertificateCa();
credentials.client_certificate = m_config.tlsClientCertificate();
credentials.client_certificate_private_key = m_config.tlsClientCertificatePrivateKey();
credentials.client_certificate_private_key_passphrase = m_config.tlsClientCertificatePrivateKeyPassphrase();
if (!proxy->centralSystemProxy()->connect(m_config.connexionUrl(), credentials))
{
cout << "Forwarded Charge point [" << proxy->identifier() << "] unable to start connection to Central System" << endl;
proxy.reset();
}
else
{
m_fowarded_chargepoints[proxy->identifier()] =
std::make_shared<HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler>(*this, proxy);
}
}
else
{
m_chargepoints[chargepoint->identifier()] =
std::shared_ptr<ChargePointRequestHandler>(new ChargePointRequestHandler(*this, chargepoint));
}
}
else
{
cout << "Charge point [" << chargepoint->identifier() << "] already forwarded" << endl;
chargepoint.reset();
}
}
else
{
cout << "Charge point [" << chargepoint->identifier() << "] already connected" << endl;
chargepoint.reset();
}
}

/** @brief Remove a charge point from the forwarded charge points */
void HybridCentralSystemEventsHandler::removeForwardedChargePoint(const std::string& identifier)
{
std::thread t(
[this, identifier = identifier]
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
m_fowarded_chargepoints.erase(identifier);
});
t.detach();
}

/** @brief Constructor */
HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::LocalControllerProxyEventsHandler(
HybridCentralSystemEventsHandler& event_handler, std::shared_ptr<ocpp::localcontroller::IChargePointProxy>& chargepoint)
: m_event_handler(event_handler), m_chargepoint(chargepoint)
{
m_chargepoint->registerListener(*this);
}

/** @brief Destructor */
HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::~LocalControllerProxyEventsHandler() { }

/** @brief Called to notify the disconnection of the charge point */
void HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::disconnectedFromChargePoint()
{
cout << "Forwarded Charge Point [" << m_chargepoint->identifier() << "] disconnected!" << endl;
m_event_handler.removeForwardedChargePoint(m_chargepoint->identifier());
}

/** @brief Called to notify the connection to the central system */
void HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::connectedToCentralSystem()
{
cout << "Forwarded Charge Point [" << m_chargepoint->identifier() << "] connected to Central System!" << endl;
}

/** @brief Called to notify the failure of the connection to the central system */
void HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::failedToConnectToCentralSystem()

{
cout << "Forwarded Charge Point [" << m_chargepoint->identifier() << "] failed to connect to Central System!" << endl;
}

/** @brief Called to notify the disconnection from the central system */
void HybridCentralSystemEventsHandler::LocalControllerProxyEventsHandler::disconnectedFromCentralSystem()
{
cout << "Forwarded Charge Point [" << m_chargepoint->identifier() << "] disconnected from Central System!" << endl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
MIT License

Copyright (c) 2020 Cedric Jimenez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef HYBRIDCENTRALSYSTEMEVENTSHANDLER_H
#define HYBRIDCENTRALSYSTEMEVENTSHANDLER_H

#include "DefaultCentralSystemEventsHandler.h"
#include "IChargePointProxy.h"
#include "LocalControllerConfig.h"

/** @brief Hybrid central system event handlers implementation for the examples */
class HybridCentralSystemEventsHandler : public DefaultCentralSystemEventsHandler
{
public:
/** @brief Constructor */
HybridCentralSystemEventsHandler(LocalControllerConfig& config,
std::filesystem::path iso_v2g_root_ca = "",
std::filesystem::path iso_mo_root_ca = "",
bool set_pending_status = false);

/** @brief Destructor */
virtual ~HybridCentralSystemEventsHandler();

// ICentralSystemEventsHandler interface

/** @copydoc bool ICentralSystemEventsHandler::chargePointConnected(std::shared_ptr<ICentralSystem::IChargePoint>) */
void chargePointConnected(std::shared_ptr<ocpp::centralsystem::ICentralSystem::IChargePoint> chargepoint) override;

/** @brief Handle events from local controller proxys */
class LocalControllerProxyEventsHandler : public ocpp::localcontroller::ILocalControllerProxyEventsHandler
{
public:
/** @brief Constructor */
LocalControllerProxyEventsHandler(HybridCentralSystemEventsHandler& event_handler,
std::shared_ptr<ocpp::localcontroller::IChargePointProxy>& chargepoint);

/** @brief Destructor */
virtual ~LocalControllerProxyEventsHandler();

/** @brief Get the charge point proxy */
std::shared_ptr<ocpp::localcontroller::IChargePointProxy> proxy() { return m_chargepoint; }

// ocpp::localcontroller::ILocalControllerProxyEventsHandler interface

/** @brief Called to notify the disconnection of the charge point */
void disconnectedFromChargePoint() override;

/** @brief Called to notify the connection to the central system */
void connectedToCentralSystem() override;

/** @brief Called to notify the failure of the connection to the central system */
void failedToConnectToCentralSystem() override;

/** @brief Called to notify the disconnection from the central system */
void disconnectedFromCentralSystem() override;

private:
/** @brief Event handler */
HybridCentralSystemEventsHandler& m_event_handler;

/** @brief Charge point proxy */
std::shared_ptr<ocpp::localcontroller::IChargePointProxy> m_chargepoint;
};

/** @brief Get the list of the forwarded charge points */
std::map<std::string, std::shared_ptr<LocalControllerProxyEventsHandler>>& forwardedChargePoints() { return m_fowarded_chargepoints; }

/** @brief Remove a charge point from the forwarded charge points */
void removeForwardedChargePoint(const std::string& identifier);

private:
/** @brief Configuration */
LocalControllerConfig& m_config;
/** @brief Forwared charge points */
std::map<std::string, std::shared_ptr<LocalControllerProxyEventsHandler>> m_fowarded_chargepoints;
};

#endif // HYBRIDCENTRALSYSTEMEVENTSHANDLER_H
31 changes: 31 additions & 0 deletions examples/quick_start_cs_lc_hybrid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Quick start Hybrid Central System / Local Controller example

## Description

This example simulates a central system which can act as a local controller and which accepts any charge point.

When the charge point identifier ends with "lc", it forwards all the requests from the Central System to the Charge Point and from the Charge Point to the Central System.

Other wise it acts as a central system.

The hybrid central system loops on its connected charge points. For each charge point it simulates the following operations :

* Get configuration

There is a 5s break between loop iterations.

## Command line

quick_start_localcontroller [-w working_dir] [-r]

* -w : Working directory where to store the configuration file (Default = current directory)
* -r : Reset all the OCPP persistent data

## Quick start with existing examples

1. Modify the ListenUrl parameter in the configuration file of the Quick Start Central System example to : ```ListenUrl=wss://127.0.0.1:8081/openocpp/```
2. Start the Quick Start Central System Example
3. Start the Quick Start Hybrid Central System / Local Controller Example
4. Start the Quick Start Charge Point Example

The Charge Point will be connected to the Central System through the Local Controller.
Loading