mikuso / ocpp-rpc

A Node.js client & server implementation of the WAMP-like RPC-over-websocket system defined in the OCPP-J protocols.
MIT License
94 stars 28 forks source link

Other way to notify the client? #26

Closed rowellcodizal closed 1 year ago

rowellcodizal commented 1 year ago

Hi @mikuso ,

asking if you have an optimized way of calling an action to the client instead of the code below:

server._clients.forEach(function each(clientrecord) { if(clientrecord.identity == 'SampleIdentity'){ clientrecord.call('StartTransactionResponse', {"timeStamp": params.timestamp}) } });

rowellcodizal commented 1 year ago

Hi @dyaacov do you have a sample code that I can use?

dyaacov commented 1 year ago

After more research, you cannot save clients in redis and then reconstruct them.

Another approach:

  1. Upon BootNotification, save client(s) in local memory as map <identifier, client>
  2. From you fontend, postman etc. send request to your server wit h identifier.
  3. You server should extract from map and invoke remote methods

Note: Things are getting complicated when we talk about horizontal scaling. Since you save clients in memory, you can use some king of pub/sub so ALL you server instances will get the message to invoke remote method, and only the server that finds the client, will be able to do so.

Thanks Dekel

mikuso commented 1 year ago

@rowellcodizal it sounds like you just want a simple way to reference a client by its identity. The module doesn't currently have a built-in way to do this so you'd have to write something yourself. For example:

// set up the server
const {RPCServer} = require('ocpp-rpc');
const server = new RPCServer({protocols: ['ocpp1.6']});
server.listen(10090); // listen on port 80

// when clients connect (after auth), store them in a Map based on their identity
const clients = new Map();
server.on('client', client => {
    clients.set(client.identity, client);
    client.once('close', () => {
        // check that we're about to delete the correct client
        if (clients.get(client.identity) === client) {
            clients.delete(client.identity);
        }
    });
});

Keep in mind that it's possible for more than 1 client to connect using the same identity at the same time, so this may or may not be adequate depending on your use case. (This is why we needed the additional check when removing a client from the Map, to ensure we're removing the correct client.)

Then later, when you need to make a request to a specific client...

const sampleClient = clients.get('SampleIdentity');
if (sampleClient) {
    await sampleClient.call('RemoteStartTransaction', {
        connectorId: 1, // start on connector 1
        idTag: 'XXXXXXXX', // using an idTag with identity 'XXXXXXXX'
    });
}

Or, if you want to make a request to all clients...

clients.forEach(async (client) => {
    await sampleClient.call('RemoteStartTransaction', {
        connectorId: 1, // start on connector 1
        idTag: 'XXXXXXXX', // using an idTag with identity 'XXXXXXXX'
    });
});
rowellcodizal commented 1 year ago

@mikuso Thank you for your suggestion; I implemented it, and it was much easier to implement than what my syntax is. Thank you, thank you.

Thanks also @dyaacov

VincentWillats commented 1 year ago

Sorry to piggy back on this now closed issue, but I am still having trouble finding a solution for this.

If storing them in a map with identity as the key, I have issues of identity possibly being the same. (I see it sets client identity from the ws url, but this isn't part of the ocpp spec so may not always be followed).

The other option is storing them in a map via serial number from the boot notification, but that leads to the issue of how to clear them out on disconnect. We do not know the clients serial number within the 'close' event.

EDIT: So the identity part IS within ocpp, apologies!

dyaacov commented 1 year ago

Hi Vincent,

"may not always be followed" Eventually, you will be the one who dictate the url to put in the charger, right?

So you will guide them to use ws://some-server/uuid-generated-by your-server

I create the charge in my portal, it generates uuid this uuid is part of the ws url

What am I missing? Dekel