Skip to content

Commit 4b89f46

Browse files
authored
Persistent v20.1 Variable and Transactions store (#379)
* add persistent Variable store * add persistent transactions queue * add further tests * update changelog * fix unit tests * fix unit tests * fix compiler warning * rename built-in VariableContainer implementations * remove leftover debug message * update WS creds storage location * pin MOSim version * update changelog
1 parent fecac09 commit 4b89f46

30 files changed

Lines changed: 2804 additions & 620 deletions

.github/workflows/documentation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
with:
3535
repository: matth-x/MicroOcppSimulator
3636
path: MicroOcppSimulator
37-
ref: feature/remote-api
37+
ref: 20e8da7b76a3f5f3e50facab018a457ecdbcca59
3838
submodules: 'recursive'
3939
- name: Clean MicroOcpp submodule
4040
run: |

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- UnlockConnector port for OCPP 2.0.1 ([#371](https://github.com/matth-x/MicroOcpp/pull/371))
3131
- More APIs ported to OCPP 2.0.1 ([#371](https://github.com/matth-x/MicroOcpp/pull/371))
3232
- Support for AuthorizeRemoteTxRequests ([#373](https://github.com/matth-x/MicroOcpp/pull/373))
33+
- Persistent Variable and Tx store for OCPP 2.0.1 ([#379](https://github.com/matth-x/MicroOcpp/pull/379))
3334

3435
### Removed
3536

src/MicroOcpp.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ void mocpp_initialize(Connection& connection, const char *bootNotificationCreden
290290
model.setVariableService(std::unique_ptr<VariableService>(
291291
new VariableService(*context, filesystem)));
292292
model.setTransactionService(std::unique_ptr<TransactionService>(
293-
new TransactionService(*context)));
293+
new TransactionService(*context, filesystem, MO_NUM_EVSEID)));
294294
model.setRemoteControlService(std::unique_ptr<RemoteControlService>(
295295
new RemoteControlService(*context, MO_NUM_EVSEID)));
296296
} else
@@ -852,6 +852,7 @@ void setEvReadyInput(std::function<bool()> evReadyInput, unsigned int connectorI
852852
evse->setEvReadyInput(evReadyInput);
853853
}
854854
}
855+
return;
855856
}
856857
#endif
857858
auto connector = context->getModel().getConnector(connectorId);

src/MicroOcpp/Model/Authorization/IdToken.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ IdToken::IdToken(const char *token, Type type, const char *memoryTag) : MemoryMa
2222
MO_DBG_ERR("invalid token");
2323
*idToken = '\0';
2424
}
25+
} else {
26+
*idToken = '\0';
2527
}
2628
}
2729

@@ -63,11 +65,11 @@ bool IdToken::parseCstr(const char *token, const char *typeCstr) {
6365
}
6466

6567
const char *IdToken::get() const {
66-
return *idToken ? idToken : nullptr;;
68+
return idToken;
6769
}
6870

6971
const char *IdToken::getTypeCstr() const {
70-
const char *res = nullptr;
72+
const char *res = "";
7173
switch (type) {
7274
case Type::UNDEFINED:
7375
MO_DBG_ERR("internal error");
@@ -98,7 +100,7 @@ const char *IdToken::getTypeCstr() const {
98100
break;
99101
}
100102

101-
return res ? res : "";
103+
return res;
102104
}
103105

104106
bool IdToken::equals(const IdToken& other) {

src/MicroOcpp/Model/ConnectorBase/Connector.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
#define MO_TXRECORD_SIZE 4 //no. of tx to hold on flash storage
2323
#endif
2424

25-
#define MAX_TX_CNT 100000U //upper limit of txNr (internal usage). Must be at least 2*MO_TXRECORD_SIZE+1
26-
2725
#ifndef MO_REPORT_NOERROR
2826
#define MO_REPORT_NOERROR 0
2927
#endif

src/MicroOcpp/Model/Metering/MeterValuesV201.cpp

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,46 @@ bool MeteringServiceEvse::existsMeasurand(const char *measurand, size_t len) {
288288
return false;
289289
}
290290

291+
namespace MicroOcpp {
292+
namespace Ocpp201 {
293+
294+
bool validateSelectString(const char *csl, void *userPtr) {
295+
auto mService = static_cast<MeteringService*>(userPtr);
296+
297+
bool isValid = true;
298+
const char *l = csl; //the beginning of an entry of the comma-separated list
299+
const char *r = l; //one place after the last character of the entry beginning with l
300+
while (*l) {
301+
if (*l == ',') {
302+
l++;
303+
continue;
304+
}
305+
r = l + 1;
306+
while (*r != '\0' && *r != ',') {
307+
r++;
308+
}
309+
bool found = false;
310+
for (size_t evseId = 0; evseId < MO_NUM_EVSEID && mService->getEvse(evseId); evseId++) {
311+
if (mService->getEvse(evseId)->existsMeasurand(l, (size_t) (r - l))) {
312+
found = true;
313+
break;
314+
}
315+
}
316+
if (!found) {
317+
isValid = false;
318+
MO_DBG_WARN("could not find metering device for %.*s", (int) (r - l), l);
319+
break;
320+
}
321+
l = r;
322+
}
323+
return isValid;
324+
}
325+
326+
} //namespace Ocpp201
327+
} //namespace MicroOcpp
328+
329+
using namespace MicroOcpp::Ocpp201;
330+
291331
MeteringService::MeteringService(Model& model, size_t numEvses) {
292332

293333
auto varService = model.getVariableService();
@@ -298,40 +338,10 @@ MeteringService::MeteringService(Model& model, size_t numEvses) {
298338
varService->declareVariable<const char*>("SampledDataCtrlr", "TxEndedMeasurands", "");
299339
varService->declareVariable<const char*>("AlignedDataCtrlr", "AlignedDataMeasurands", "");
300340

301-
std::function<bool(const char*)> validateSelectString = [this] (const char *csl) {
302-
bool isValid = true;
303-
const char *l = csl; //the beginning of an entry of the comma-separated list
304-
const char *r = l; //one place after the last character of the entry beginning with l
305-
while (*l) {
306-
if (*l == ',') {
307-
l++;
308-
continue;
309-
}
310-
r = l + 1;
311-
while (*r != '\0' && *r != ',') {
312-
r++;
313-
}
314-
bool found = false;
315-
for (size_t evseId = 0; evseId < MO_NUM_EVSEID && evses[evseId]; evseId++) {
316-
if (evses[evseId]->existsMeasurand(l, (size_t) (r - l))) {
317-
found = true;
318-
break;
319-
}
320-
}
321-
if (!found) {
322-
isValid = false;
323-
MO_DBG_WARN("could not find metering device for %.*s", (int) (r - l), l);
324-
break;
325-
}
326-
l = r;
327-
}
328-
return isValid;
329-
};
330-
331-
varService->registerValidator<const char*>("SampledDataCtrlr", "TxStartedMeasurands", validateSelectString);
332-
varService->registerValidator<const char*>("SampledDataCtrlr", "TxUpdatedMeasurands", validateSelectString);
333-
varService->registerValidator<const char*>("SampledDataCtrlr", "TxEndedMeasurands", validateSelectString);
334-
varService->registerValidator<const char*>("AlignedDataCtrlr", "AlignedDataMeasurands", validateSelectString);
341+
varService->registerValidator<const char*>("SampledDataCtrlr", "TxStartedMeasurands", validateSelectString, this);
342+
varService->registerValidator<const char*>("SampledDataCtrlr", "TxUpdatedMeasurands", validateSelectString, this);
343+
varService->registerValidator<const char*>("SampledDataCtrlr", "TxEndedMeasurands", validateSelectString, this);
344+
varService->registerValidator<const char*>("AlignedDataCtrlr", "AlignedDataMeasurands", validateSelectString, this);
335345

336346
for (size_t evseId = 0; evseId < std::min(numEvses, (size_t)MO_NUM_EVSEID); evseId++) {
337347
evses[evseId] = new MeteringServiceEvse(model, evseId);

src/MicroOcpp/Model/RemoteControl/RemoteControlService.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ UnlockStatus RemoteControlServiceEvse::unlockConnector() {
4040
if (tx->started && !tx->stopped && tx->isAuthorized) {
4141
return UnlockStatus_OngoingAuthorizedTransaction;
4242
} else {
43-
evse->abortTransaction(Ocpp201::Transaction::StopReason::Other,Ocpp201::TransactionEventTriggerReason::UnlockCommand);
43+
evse->abortTransaction(Ocpp201::Transaction::StoppedReason::Other,Ocpp201::TransactionEventTriggerReason::UnlockCommand);
4444
}
4545
}
4646
}
@@ -102,7 +102,7 @@ RemoteControlServiceEvse *RemoteControlService::getEvse(unsigned int evseId) {
102102
return evses[evseId];
103103
}
104104

105-
RequestStartStopStatus RemoteControlService::requestStartTransaction(unsigned int evseId, unsigned int remoteStartId, IdToken idToken, std::shared_ptr<Ocpp201::Transaction>& transactionOut) {
105+
RequestStartStopStatus RemoteControlService::requestStartTransaction(unsigned int evseId, unsigned int remoteStartId, IdToken idToken, char *transactionIdOut, size_t transactionIdBufSize) {
106106

107107
TransactionService *txService = context.getModel().getTransactionService();
108108
if (!txService) {
@@ -116,21 +116,32 @@ RequestStartStopStatus RemoteControlService::requestStartTransaction(unsigned in
116116
return RequestStartStopStatus_Rejected;
117117
}
118118

119-
transactionOut = evse->getTransaction();
120-
121119
if (!evse->beginAuthorization(idToken, authorizeRemoteStart->getBool())) {
122120
MO_DBG_INFO("EVSE still occupied with pending tx");
121+
if (auto tx = evse->getTransaction()) {
122+
auto ret = snprintf(transactionIdOut, transactionIdBufSize, "%s", tx->transactionId);
123+
if (ret < 0 || (size_t)ret >= transactionIdBufSize) {
124+
MO_DBG_ERR("internal error");
125+
return RequestStartStopStatus_Rejected;
126+
}
127+
}
128+
return RequestStartStopStatus_Rejected;
129+
}
130+
131+
auto tx = evse->getTransaction();
132+
if (!tx) {
133+
MO_DBG_ERR("internal error");
123134
return RequestStartStopStatus_Rejected;
124135
}
125136

126-
transactionOut = evse->getTransaction();
127-
if (!transactionOut) {
137+
auto ret = snprintf(transactionIdOut, transactionIdBufSize, "%s", tx->transactionId);
138+
if (ret < 0 || (size_t)ret >= transactionIdBufSize) {
128139
MO_DBG_ERR("internal error");
129140
return RequestStartStopStatus_Rejected;
130141
}
131142

132-
transactionOut->remoteStartId = remoteStartId;
133-
transactionOut->notifyRemoteStartId = true;
143+
tx->remoteStartId = remoteStartId;
144+
tx->notifyRemoteStartId = true;
134145

135146
return RequestStartStopStatus_Accepted;
136147
}
@@ -148,7 +159,7 @@ RequestStartStopStatus RemoteControlService::requestStopTransaction(const char *
148159
for (unsigned int evseId = 0; evseId < MO_NUM_EVSEID; evseId++) {
149160
if (auto evse = txService->getEvse(evseId)) {
150161
if (evse->getTransaction() && !strcmp(evse->getTransaction()->transactionId, transactionId)) {
151-
success = evse->abortTransaction(Ocpp201::Transaction::StopReason::Remote, Ocpp201::TransactionEventTriggerReason::RemoteStop);
162+
success = evse->abortTransaction(Ocpp201::Transaction::StoppedReason::Remote, Ocpp201::TransactionEventTriggerReason::RemoteStop);
152163
break;
153164
}
154165
}

src/MicroOcpp/Model/RemoteControl/RemoteControlService.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class RemoteControlService : public MemoryManaged {
5353

5454
RemoteControlServiceEvse *getEvse(unsigned int evseId);
5555

56-
RequestStartStopStatus requestStartTransaction(unsigned int evseId, unsigned int remoteStartId, IdToken idToken, std::shared_ptr<Ocpp201::Transaction>& transactionOut); //ChargingProfile, GroupIdToken not supported yet
56+
RequestStartStopStatus requestStartTransaction(unsigned int evseId, unsigned int remoteStartId, IdToken idToken, char *transactionIdOut, size_t transactionIdBufSize); //ChargingProfile, GroupIdToken not supported yet
5757

5858
RequestStartStopStatus requestStopTransaction(const char *transactionId);
5959
};

src/MicroOcpp/Model/Reset/ResetService.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ ResetService::~ResetService() {
125125

126126
ResetService::Evse::Evse(Context& context, ResetService& resetService, unsigned int evseId) : context(context), resetService(resetService), evseId(evseId) {
127127
auto varService = context.getModel().getVariableService();
128-
varService->declareVariable<bool>(ComponentId("EVSE", evseId >= 1 ? evseId : -1), "AllowReset", true, MO_VARIABLE_FN, Variable::Mutability::ReadOnly);
128+
varService->declareVariable<bool>(ComponentId("EVSE", evseId >= 1 ? evseId : -1), "AllowReset", true, Variable::Mutability::ReadOnly, false);
129129
}
130130

131131
void ResetService::Evse::loop() {
@@ -303,7 +303,7 @@ ResetStatus ResetService::initiateReset(ResetType type, unsigned int evseId) {
303303
if (tx->active) {
304304
//Tx in progress. Check behavior
305305
if (type == ResetType_Immediate) {
306-
txService->getEvse(eId)->abortTransaction(Transaction::StopReason::ImmediateReset, TransactionEventTriggerReason::ResetCommand);
306+
txService->getEvse(eId)->abortTransaction(Transaction::StoppedReason::ImmediateReset, TransactionEventTriggerReason::ResetCommand);
307307
} else {
308308
scheduled = true;
309309
break;

0 commit comments

Comments
 (0)