steve-community / steve

SteVe - OCPP server implementation in Java
GNU General Public License v3.0
801 stars 393 forks source link

Connection Remain open in case of power loss #357

Open giorgio80 opened 4 years ago

giorgio80 commented 4 years ago

Hello,

I have tested this scenario:

when a chargepoint loose connection (ex. power loss ) without sending any closing request, the connection still remain open on Steve ( still looks like a connected chargepoint)

When reconnecting I can notice 2 different connection with same chargepoint id.
Is there any way to avoid this ? also tried to set a lower interval of heartbeat but missed heartbeat still not close the connection

Thanks

goekay commented 4 years ago

unfortunately, steve is not directly notified about these situations, since the connection is dropped silently on the chargepoint end. there are websocket ping-pongs (similar to ocpp heartbeat, but a lower level ws-specific mechanism) which we are using to keep the connections open (by preventing them from being idle).

by default, the ping-pong interval is set to 15 minutes. we can set this to a lower value and react to an exception (if it fails) by deleting this connection.

giorgio80 commented 4 years ago

I think that putting a ping-pongs to keeps-alive and reducing the 15 minutes would be a good way to approach. Just wondering why put ocpp heartbeat and redundant ping pong ( not about your software clearly but about ocpp architecture) . Btw thanks, explanation is really really clear.

goekay commented 4 years ago

ping-pongs are specific to websocket. the ocpp version supporting json, that use websocket connections, came later. before that, ocpp was based on soap and with soap they needed a mechanism to let the backend know that the station is still alive.

goekay commented 4 years ago

@giorgio80 i need your help with this, since i don't have access to charging stations.

can you please set the ping-pong to 1 minute and observe the logs to see what kind of exception happens if the connection cannot be used.

then i can implement the necessary logic to remove such sessions.

giorgio80 commented 4 years ago

Hi , Sure , i try and let u know . in case as i’m also developer of ocpp hardware i can connect one of my stations to your server . Let me know

giorgio80 commented 4 years ago

hello @goekay , I made some tests.. and put really easy task to kill the session if ping fails :

{
        WebSocketLogger.sendingPing(chargeBoxId, session);
        try {
            session.sendMessage(PING_MESSAGE);
        } catch (IOException e) {
            WebSocketLogger.pingError(chargeBoxId, session, e);
            // TODO: Do something about this
            try {
                session.close();
                log.error("PONG FAILED FOR " + chargeBoxId + " try to close connection");
            } catch (IOException ex) {
                log.error("FAILED TO CLOSE CONNECTION FOR "+chargeBoxId);
            }
        }
    }

An hardware producer point of view:

1) Some c++ library for Websocket implement ping/pong others not, others again are not native in sense that they expose the callback but you have to pong back manually.

2) not all HW producer, especially for ws , manage the ping/pong routine ( i also added this firmware side to make it working) so it should / can be an option related to the chargepoint itself as can work with some stations but not with others.

Let me know if need support for hw attaching ocpp station to your side (ocpp1.6J)

goekay commented 4 years ago

@giorgio80 thanks for your input. yes, we could implement session closing like your code snippet. however, there is one problem with it: it makes a too broad generalisation and closes the session for every kind of exception. this is probably not correct. we should be more specific and close the session only for the exception that is caused by a dead connection.

my initial thought was similar but with the following decision logic:

if (e instanceof X) {
    try {
        log.error("PONG FAILED FOR " + chargeBoxId + " try to close connection");
        session.close();
    } catch (IOException ex) {
        log.error("FAILED TO CLOSE CONNECTION FOR "+chargeBoxId);
    }
}

and X would be this exception type.

giorgio80 commented 4 years ago

@goekay yes, you right , I noticed this in fact on log 👍 gonna work on that and let u know. let me know if hw support is needed I can help u