Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First push of more advanced version of OCPP binding. #91

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
import java.util.HashSet;
import java.util.Set;
import org.connectorio.addons.binding.BaseBindingConstants;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.UID;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeUID;

public interface OcppBindingConstants extends BaseBindingConstants {

Expand All @@ -37,4 +41,40 @@ public interface OcppBindingConstants extends BaseBindingConstants {
CONNECTOR_THING_TYPE
));

// common channel types
ChannelRef CURRENT_EXPORT = new ChannelRef("currentExport");
ChannelRef CURRENT_IMPORT = new ChannelRef("currentImport");
ChannelRef CURRENT_OFFERED = new ChannelRef("currentOffered");
ChannelRef ENERGY_ACTIVE_EXPORT = new ChannelRef("energyActiveExport");
ChannelRef ENERGY_ACTIVE_IMPORT = new ChannelRef("energyActiveImport");
ChannelRef ENERGY_REACTIVE_EXPORT = new ChannelRef("energyReactiveExport");
ChannelRef ENERGY_REACTIVE_IMPORT = new ChannelRef("energyReactiveImport");
ChannelRef ENERGY_ACTIVE_EXPORT_INTERVAL = new ChannelRef("energyActiveExportInterval");
ChannelRef ENERGY_ACTIVE_IMPORT_INTERVAL = new ChannelRef("energyActiveImportInterval");
ChannelRef ENERGY_REACTIVE_EXPORT_INTERVAL = new ChannelRef("energyReactiveExportInterval");
ChannelRef ENERGY_REACTIVE_IMPORT_INTERVAL = new ChannelRef("energyReactiveImportInterval");
ChannelRef FREQUENCY = new ChannelRef("frequency");
ChannelRef POWER_ACTIVE_EXPORT = new ChannelRef("powerActiveExport");
ChannelRef POWER_ACTIVE_IMPORT = new ChannelRef("powerActiveImport");
ChannelRef POWER_FACTOR = new ChannelRef("powerFactor");
ChannelRef POWER_OFFERED = new ChannelRef("powerOffered");
ChannelRef POWER_REACTIVE_EXPORT = new ChannelRef("powerReactiveExport");
ChannelRef POWER_REACTIVE_IMPORT = new ChannelRef("powerReactiveImport");
ChannelRef RPM = new ChannelRef("rpm");
ChannelRef SOC = new ChannelRef("soc");
ChannelRef TEMPERATURE = new ChannelRef("temperature");
ChannelRef VOLTAGE = new ChannelRef("voltage");

static class ChannelRef extends UID {

public ChannelRef(String uid) {
super(uid);
}

@Override
protected int getMinimalNumberOfSegments() {
return 1;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
import eu.chargetime.ocpp.model.Request;
import java.util.UUID;
import java.util.concurrent.CompletionStage;
import org.connectorio.addons.binding.ocpp.internal.server.ChargerReference;

public interface OcppSender {

<T extends Confirmation> CompletionStage<T> send(UUID sessionIndex, Request request);
<T extends Confirmation> CompletionStage<T> send(ChargerReference reference, Request request);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.connectorio.addons.binding.ocpp.internal.discovery;

import eu.chargetime.ocpp.model.core.StatusNotificationRequest;
import java.util.Collections;
import org.connectorio.addons.binding.ocpp.OcppBindingConstants;
import org.connectorio.addons.binding.ocpp.internal.OcppRequestListener;
import org.connectorio.addons.binding.ocpp.internal.handler.ChargerThingHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;

import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;

public class OcppChargerConnectorDiscoveryService extends AbstractDiscoveryService implements DiscoveryService,
ThingHandlerService, OcppRequestListener<StatusNotificationRequest> {

private ChargerThingHandler thingHandler;

public OcppChargerConnectorDiscoveryService() {
super(Collections.singleton(OcppBindingConstants.CONNECTOR_THING_TYPE), 30, true);
}

@Override
protected void startScan() {
}

@Override
public void setThingHandler(ThingHandler handler){
if (handler instanceof ChargerThingHandler) {
thingHandler = (ChargerThingHandler) handler;
thingHandler.addRequestListener(StatusNotificationRequest.class, this);
}
}

@Override
public ThingHandler getThingHandler() {
return thingHandler;
}

@Override
public void activate() {
ThingHandlerService.super.activate();
}

@Override
public void deactivate() {
thingHandler.removeRequestListener(this);
ThingHandlerService.super.deactivate();
}

@Override
public void onRequest(StatusNotificationRequest request) {
ThingUID bridgeUid = thingHandler.getThing().getUID();

Integer connectorId = request.getConnectorId();
if (connectorId != null && connectorId > 0) {
// connectorId = 0 indicates status of charge point controller
ThingUID thingUID = new ThingUID(OcppBindingConstants.CONNECTOR_THING_TYPE, bridgeUid, "" + connectorId);
DiscoveryResultBuilder resultBuilder = DiscoveryResultBuilder.create(thingUID)
.withBridge(bridgeUid)
.withProperty("connectorId", connectorId)
.withRepresentationProperty("connectorId")
.withLabel("Connector #" + request.getConnectorId());
thingDiscovered(resultBuilder.build());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void onRequest(BootNotificationRequest request) {
DiscoveryResultBuilder resultBuilder = DiscoveryResultBuilder.create(thingUID)
.withBridge(bridgeUid)
.withProperty(Thing.PROPERTY_MODEL_ID, request.getChargePointModel())
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, request.getMeterSerialNumber())
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, request.getChargePointSerialNumber())
.withProperty(Thing.PROPERTY_VENDOR, request.getChargePointVendor())
.withProperty(Thing.PROPERTY_FIRMWARE_VERSION, request.getFirmwareVersion())
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.connectorio.addons.binding.ocpp.internal.handler;

import eu.chargetime.ocpp.model.Request;
import eu.chargetime.ocpp.model.core.MeterValuesConfirmation;
import eu.chargetime.ocpp.model.core.MeterValuesRequest;
import eu.chargetime.ocpp.model.core.StartTransactionConfirmation;
import eu.chargetime.ocpp.model.core.StartTransactionRequest;
import eu.chargetime.ocpp.model.core.StatusNotificationConfirmation;
import eu.chargetime.ocpp.model.core.StatusNotificationRequest;
import eu.chargetime.ocpp.model.core.StopTransactionConfirmation;
import eu.chargetime.ocpp.model.core.StopTransactionRequest;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.connectorio.addons.binding.ocpp.internal.OcppRequestListener;
import org.connectorio.addons.binding.ocpp.internal.server.listener.MeterValuesHandler;
import org.connectorio.addons.binding.ocpp.internal.server.listener.StatusNotificationHandler;
import org.connectorio.addons.binding.ocpp.internal.server.listener.TransactionHandler;

public class ChargerConnectorAdapter implements StatusNotificationHandler, MeterValuesHandler,
TransactionHandler {

private final Map<Integer, ConnectorThingHandler> handlers = new ConcurrentHashMap<>();
private final Map<Integer, Integer> transactionMap = new ConcurrentHashMap<>();
private final OcppRequestListener<Request> listener;

public ChargerConnectorAdapter(OcppRequestListener<Request> listener) {
this.listener = listener;
}

public void addConnector(int connector, ConnectorThingHandler handler) {
handlers.put(connector, handler);
}

public void removeConnector(int connector) {
handlers.remove(connector);
}

@Override
public StatusNotificationConfirmation handleStatusNotification(StatusNotificationRequest request) {
listener.onRequest(request);
return handle(handler -> handler.handleStatusNotification(request), request.getConnectorId());
}

@Override
public MeterValuesConfirmation handleMeterValues(MeterValuesRequest request) {
listener.onRequest(request);
return handle(handler -> handler.handleMeterValues(request), request.getConnectorId());
}

@Override
public StartTransactionConfirmation handleStartTransaction(StartTransactionRequest request) {
listener.onRequest(request);

StartTransactionConfirmation confirmation = handle(handler -> handler.handleStartTransaction(request), request.getConnectorId());
if (confirmation != null) {
transactionMap.put(request.getConnectorId(), confirmation.getTransactionId());
}
return confirmation;
}

@Override
public StopTransactionConfirmation handleStopTransaction(StopTransactionRequest request) {
listener.onRequest(request);
Integer connectorId = null;
for (Entry<Integer, Integer> entry : transactionMap.entrySet()) {
if (entry.getValue().equals(request.getTransactionId())) {
connectorId = entry.getKey();
}
}

if (connectorId != null) {
return handle(handler -> handler.handleStopTransaction(request), connectorId);
}
// unknown transaction
return null;
}

private <C> C handle(Function<ConnectorThingHandler, C> handler, int connector) {
if (handlers.containsKey(connector)) {
ConnectorThingHandler connectorHandler = handlers.get(connector);
return handler.apply(connectorHandler);
}

return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,150 @@
*/
package org.connectorio.addons.binding.ocpp.internal.handler;

import org.connectorio.addons.binding.handler.GenericThingHandlerBase;
import org.connectorio.addons.binding.handler.polling.common.BasePollingThingHandler;
import eu.chargetime.ocpp.model.Request;
import eu.chargetime.ocpp.model.core.HeartbeatConfirmation;
import eu.chargetime.ocpp.model.core.HeartbeatRequest;
import eu.chargetime.ocpp.model.core.MeterValuesConfirmation;
import eu.chargetime.ocpp.model.core.MeterValuesRequest;
import eu.chargetime.ocpp.model.core.StartTransactionConfirmation;
import eu.chargetime.ocpp.model.core.StartTransactionRequest;
import eu.chargetime.ocpp.model.core.StatusNotificationConfirmation;
import eu.chargetime.ocpp.model.core.StatusNotificationRequest;
import eu.chargetime.ocpp.model.core.StopTransactionConfirmation;
import eu.chargetime.ocpp.model.core.StopTransactionRequest;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collection;
import org.connectorio.addons.binding.handler.GenericBridgeHandlerBase;
import org.connectorio.addons.binding.ocpp.internal.OcppAttendant;
import org.connectorio.addons.binding.ocpp.internal.OcppRequestListener;
import org.connectorio.addons.binding.ocpp.internal.config.ChargerConfig;
import org.connectorio.addons.binding.ocpp.internal.discovery.OcppChargerConnectorDiscoveryService;
import org.connectorio.addons.binding.ocpp.internal.server.CompositeRequestListener;
import org.connectorio.addons.binding.ocpp.internal.server.listener.HeartbeatHandler;
import org.connectorio.addons.binding.ocpp.internal.server.listener.MeterValuesHandler;
import org.connectorio.addons.binding.ocpp.internal.server.listener.StatusNotificationHandler;
import org.connectorio.addons.binding.ocpp.internal.server.listener.TransactionHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChargerThingHandler extends GenericThingHandlerBase<ServerBridgeHandler, ChargerConfig> {
public class ChargerThingHandler extends GenericBridgeHandlerBase<ChargerConfig> implements
HeartbeatHandler, StatusNotificationHandler, TransactionHandler, MeterValuesHandler,
OcppAttendant {

public ChargerThingHandler(Thing thing) {
super(thing);
private final Logger logger = LoggerFactory.getLogger(ConnectorThingHandler.class);
private final CompositeRequestListener listener = new CompositeRequestListener();
private final ChargerConnectorAdapter adapter = new ChargerConnectorAdapter(listener);

public ChargerThingHandler(Bridge bridge) {
super(bridge);
}


@Override
public void initialize() {
updateStatus(ThingStatus.ONLINE);
}

@Override
public void dispose() {
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {

}

@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Arrays.asList(OcppChargerConnectorDiscoveryService.class);
}

@Override
public HeartbeatConfirmation handleHeartbeat(HeartbeatRequest request) {
updateStatus(ThingStatus.ONLINE);
return new HeartbeatConfirmation(ZonedDateTime.now());
}

@Override
public MeterValuesConfirmation handleMeterValues(MeterValuesRequest request) {
updateStatus(ThingStatus.ONLINE);
return adapter.handleMeterValues(request);
}

@Override
public StatusNotificationConfirmation handleStatusNotification(StatusNotificationRequest request) {
updateStatus(ThingStatus.ONLINE);

StatusNotificationConfirmation confirmation = adapter.handleStatusNotification(request);

if (confirmation == null) {
return new StatusNotificationConfirmation();
}
return confirmation;
}

@Override
public StartTransactionConfirmation handleStartTransaction(StartTransactionRequest request) {
updateStatus(ThingStatus.ONLINE);
return adapter.handleStartTransaction(request);
}

@Override
public StopTransactionConfirmation handleStopTransaction(StopTransactionRequest request) {
updateStatus(ThingStatus.ONLINE);
return adapter.handleStopTransaction(request);
}

@Override
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
if (childHandler instanceof ConnectorThingHandler) {
Integer connectorId = getConnectorId(childThing);
if (connectorId != null) {
adapter.addConnector(connectorId, (ConnectorThingHandler) childHandler);
}
}
}

@Override
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
Integer connectorId = getConnectorId(childThing);
if (connectorId != null) {
adapter.removeConnector(connectorId);
}
}

@Override
public <T extends Request> boolean addRequestListener(Class<T> type, OcppRequestListener<T> listener) {
return this.listener.addRequestListener(type, listener);
}

@Override
public <T extends Request> void removeRequestListener(OcppRequestListener<T> listener) {
this.listener.removeRequestListener(listener);
}

private Integer getConnectorId(Thing childThing) {
Object connectorId = childThing.getConfiguration().get("connectorId");
if (connectorId instanceof Number) {
return ((Number) connectorId).intValue();
}
if (connectorId instanceof String) {
try {
return Integer.parseInt((String) connectorId);
} catch (NumberFormatException e) {
logger.warn("Invalid format of connectorId config parameter {}", connectorId, e);
return null;
}
}
return null;
}

}
Loading
Loading