diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/OcppBindingConstants.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/OcppBindingConstants.java index d439c353..ce8e85b0 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/OcppBindingConstants.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/OcppBindingConstants.java @@ -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 { @@ -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; + } + } + } diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/OcppSender.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/OcppSender.java index 6d737863..ab862f1d 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/OcppSender.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/OcppSender.java @@ -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 { - CompletionStage send(UUID sessionIndex, Request request); + CompletionStage send(ChargerReference reference, Request request); } diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerConnectorDiscoveryService.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerConnectorDiscoveryService.java new file mode 100644 index 00000000..bf3cc024 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerConnectorDiscoveryService.java @@ -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 { + + 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()); + } + } +} \ No newline at end of file diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerDiscoveryService.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerDiscoveryService.java index 0a99d34a..a7d66d9d 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerDiscoveryService.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/discovery/OcppChargerDiscoveryService.java @@ -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) diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerConnectorAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerConnectorAdapter.java new file mode 100644 index 00000000..75b81718 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerConnectorAdapter.java @@ -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 handlers = new ConcurrentHashMap<>(); + private final Map transactionMap = new ConcurrentHashMap<>(); + private final OcppRequestListener listener; + + public ChargerConnectorAdapter(OcppRequestListener 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 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 handle(Function handler, int connector) { + if (handlers.containsKey(connector)) { + ConnectorThingHandler connectorHandler = handlers.get(connector); + return handler.apply(connectorHandler); + } + + return null; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerThingHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerThingHandler.java index cd17061b..5f11e936 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerThingHandler.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ChargerThingHandler.java @@ -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 { +public class ChargerThingHandler extends GenericBridgeHandlerBase 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> 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 boolean addRequestListener(Class type, OcppRequestListener listener) { + return this.listener.addRequestListener(type, listener); + } + + @Override + public void removeRequestListener(OcppRequestListener 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; + } + } diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ConnectorThingHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ConnectorThingHandler.java new file mode 100644 index 00000000..07ecd7ae --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ConnectorThingHandler.java @@ -0,0 +1,159 @@ +package org.connectorio.addons.binding.ocpp.internal.handler; + +import eu.chargetime.ocpp.model.core.AuthorizationStatus; +import eu.chargetime.ocpp.model.core.ChargePointStatus; +import eu.chargetime.ocpp.model.core.IdTagInfo; +import eu.chargetime.ocpp.model.core.MeterValue; +import eu.chargetime.ocpp.model.core.MeterValuesConfirmation; +import eu.chargetime.ocpp.model.core.MeterValuesRequest; +import eu.chargetime.ocpp.model.core.SampledValue; +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 eu.chargetime.ocpp.model.core.ValueFormat; +import java.time.ZonedDateTime; +import java.util.concurrent.atomic.AtomicInteger; +import org.connectorio.addons.binding.handler.GenericThingHandlerBase; +import org.connectorio.addons.binding.ocpp.internal.config.ChargerConfig; +import org.connectorio.addons.binding.ocpp.internal.server.OcppMeasurementMapping; +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.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.UID; +import org.openhab.core.thing.binding.ThingHandlerCallback; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import tec.uom.se.ComparableQuantity; +import tec.uom.se.quantity.Quantities; + +public class ConnectorThingHandler extends GenericThingHandlerBase implements + StatusNotificationHandler, TransactionHandler, MeterValuesHandler { + + private final AtomicInteger transactionId = new AtomicInteger(); + private final Logger logger = LoggerFactory.getLogger(ConnectorThingHandler.class); + + public ConnectorThingHandler(Thing thing) { + super(thing); + } + + @Override + public void initialize() { + updateStatus(ThingStatus.ONLINE); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + + } + + @Override + public MeterValuesConfirmation handleMeterValues(MeterValuesRequest request) { + ThingHandlerCallback callback = getCallback(); + + // push transaction id + Integer transactionId = request.getTransactionId(); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "transactionId"), new DecimalType(transactionId)); + + for (MeterValue value : request.getMeterValue()) { + ZonedDateTime timestamp = value.getTimestamp(); + // update timestamp for further channel updates + callback.stateUpdated(new ChannelUID(getThing().getUID(), "timestamp"), new DateTimeType(timestamp)); + + logger.debug("Received samples for transaction {}: {}", transactionId, value); + + for (SampledValue sample : value.getSampledValue()) { + if (!ValueFormat.Raw.equals(sample.getFormat())) { + // unsupported case with encrypted measurements + continue; + } + + try { + Double measurement = Double.valueOf(sample.getValue()); + UID ref = OcppMeasurementMapping.get(sample.getMeasurand()); + if (ref != null) { + ChannelUID uid = new ChannelUID(getThing().getUID(), ref.getAsString()); + State state = parse(measurement, uid, sample); + getCallback().stateUpdated(uid, state); + } + } catch (NumberFormatException e) { + logger.debug("Could not parse value of measurement {}", sample, e); + } + } + } + + return new MeterValuesConfirmation(); + } + + @Override + public StatusNotificationConfirmation handleStatusNotification(StatusNotificationRequest request) { + ChargePointStatus status = request.getStatus(); + + StringType val = new StringType(status.name()); + getCallback().stateUpdated(new ChannelUID(getThing().getUID(), "chargePointStatus"), val); + + return new StatusNotificationConfirmation(); + } + + @Override + public StartTransactionConfirmation handleStartTransaction(StartTransactionRequest request) { + String tag = request.getIdTag(); + + ThingHandlerCallback callback = getCallback(); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "idTag"), new StringType(tag)); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "timestampStart"), new DateTimeType(request.getTimestamp())); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "meterStart"), new QuantityType<>(request.getMeterStart(), Units.WATT_HOUR)); + + IdTagInfo tagInfo = new IdTagInfo(AuthorizationStatus.Accepted); + return new StartTransactionConfirmation(tagInfo, generateId()); + } + + @Override + public StopTransactionConfirmation handleStopTransaction(StopTransactionRequest request) { + String tag = request.getIdTag(); + + Integer txId = request.getTransactionId(); + if (transactionId.get() != txId + 1) { + return new StopTransactionConfirmation(); + } + + ThingHandlerCallback callback = getCallback(); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "idTag"), new StringType(tag)); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "timestampStop"), new DateTimeType(request.getTimestamp())); + callback.stateUpdated(new ChannelUID(getThing().getUID(), "meterStop"), new QuantityType<>(request.getMeterStop(), Units.WATT_HOUR)); + + return new StopTransactionConfirmation(); + } + + private static State parse(Double measurement, ChannelUID uid, SampledValue sample) { + String unit = sample.getUnit(); + if (unit != null) { + ComparableQuantity quantity = Quantities.getQuantity("1 " + unit); + return new QuantityType<>(measurement, quantity.getUnit()); + } + + // default assumed from specs, when unit is not specified it fall backs to "Wh" + return new QuantityType<>(measurement, Units.WATT_HOUR); + } + + private int generateId() { + int transaction = transactionId.getAndIncrement(); + if (transaction == Integer.MAX_VALUE) { + transactionId.set(0); + } + return transaction; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/OcppThingHandlerFactory.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/OcppThingHandlerFactory.java index dcdddd25..edb04299 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/OcppThingHandlerFactory.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/OcppThingHandlerFactory.java @@ -45,11 +45,14 @@ protected ThingHandler createHandler(Thing thing) { if (thing.getThingTypeUID().equals(OcppBindingConstants.SERVER_THING_TYPE)) { return new ServerBridgeHandler((Bridge) thing, networkAddressService); } - } else { if (thing.getThingTypeUID().equals(OcppBindingConstants.CHARGER_THING_TYPE)) { - return new ChargerThingHandler(thing); + return new ChargerThingHandler((Bridge) thing); } } + + if (thing.getThingTypeUID().equals(OcppBindingConstants.CONNECTOR_THING_TYPE)) { + return new ConnectorThingHandler(thing); + } return null; } } \ No newline at end of file diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeDispatcherAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeDispatcherAdapter.java new file mode 100644 index 00000000..521368ca --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeDispatcherAdapter.java @@ -0,0 +1,75 @@ +package org.connectorio.addons.binding.ocpp.internal.handler; + +import eu.chargetime.ocpp.model.Confirmation; +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.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import org.connectorio.addons.binding.ocpp.internal.server.ChargerReference; +import org.connectorio.addons.binding.ocpp.internal.server.OcppChargerSessionRegistry; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.CoreEventHandlerAdapter; + +public class ServerBridgeDispatcherAdapter extends CoreEventHandlerAdapter { + + private final Map handlers = new ConcurrentHashMap<>(); + private final OcppChargerSessionRegistry sessionRegistry; + + public ServerBridgeDispatcherAdapter(OcppChargerSessionRegistry sessionRegistry) { + this.sessionRegistry = sessionRegistry; + } + + public void addHandler(ChargerReference reference, ChargerThingHandler handler) { + this.handlers.put(reference, handler); + } + + public void removeHandler(ChargerReference reference) { + this.handlers.remove(reference); + } + + @Override + public HeartbeatConfirmation handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) { + return handle(sessionIndex, handler -> handler.handleHeartbeat(request)); + } + + @Override + public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, MeterValuesRequest request) { + return handle(sessionIndex, handler -> handler.handleMeterValues(request)); + } + + @Override + public StartTransactionConfirmation handleStartTransactionRequest(UUID sessionIndex, StartTransactionRequest request) { + return handle(sessionIndex, handler -> handler.handleStartTransaction(request)); + } + + @Override + public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessionIndex, StatusNotificationRequest request) { + return handle(sessionIndex, handler -> handler.handleStatusNotification(request)); + } + + @Override + public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { + return handle(sessionIndex, handler -> handler.handleStopTransaction(request)); + } + + private C handle(UUID sessionIndex, Function consumer) { + ChargerReference charger = sessionRegistry.getCharger(sessionIndex); + if (charger != null) { + ChargerThingHandler handler = handlers.get(charger); + if (handler != null) { + return consumer.apply(handler); + } + } + return null; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeHandler.java index c59ad5ec..6edd51b9 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeHandler.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/handler/ServerBridgeHandler.java @@ -17,34 +17,44 @@ */ package org.connectorio.addons.binding.ocpp.internal.handler; +import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; import eu.chargetime.ocpp.model.Request; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.stream.Collectors; 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.ServerConfig; import org.connectorio.addons.binding.ocpp.internal.discovery.OcppChargerDiscoveryService; +import org.connectorio.addons.binding.ocpp.internal.server.ChargerReference; import org.connectorio.addons.binding.ocpp.internal.server.CompositeRequestListener; import org.connectorio.addons.binding.ocpp.internal.server.OcppServer; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.AuthorizationIdTagAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.BootRegistrationAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.RequestListenerAdapter; import org.openhab.core.net.NetworkAddressService; 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.ThingStatusDetail; +import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; public class ServerBridgeHandler extends GenericBridgeHandlerBase implements OcppAttendant { + private final CompositeRequestListener listener = new CompositeRequestListener(); + private NetworkAddressService networkAddressService; private OcppServer server; - - private CompositeRequestListener listener = new CompositeRequestListener(); + private ServerBridgeDispatcherAdapter bridgeHandler; public ServerBridgeHandler(Bridge bridge, NetworkAddressService networkAddressService) { super(bridge); @@ -71,7 +81,18 @@ public void initialize() { Set chargers = set(config.chargers); Set tags = set(config.tags); - server = new OcppServer(address, config.port, listener, chargers, tags); + + BootRegistrationAdapter bootAdapter = new BootRegistrationAdapter(chargers); + bridgeHandler = new ServerBridgeDispatcherAdapter(bootAdapter); + Deque eventHandlers = new ConcurrentLinkedDeque<>(); + // 2nd adapter + eventHandlers.addFirst(new AuthorizationIdTagAdapter(tags)); + // 1st adapter + eventHandlers.addFirst(bootAdapter); + eventHandlers.add(bridgeHandler); + eventHandlers.add(new RequestListenerAdapter(listener)); + + server = new OcppServer(address, config.port, bootAdapter, eventHandlers); server.activate(); updateStatus(ThingStatus.ONLINE); } @@ -81,6 +102,9 @@ public void dispose() { if (server != null) { server.close(); } + if (bridgeHandler != null) { + bridgeHandler = null; + } } private Set set(List config) { @@ -98,6 +122,22 @@ public void handleCommand(ChannelUID channelUID, Command command) { } + @Override + public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) { + Object serial = childThing.getConfiguration().get(Thing.PROPERTY_SERIAL_NUMBER); + if (serial instanceof String && bridgeHandler != null && childHandler instanceof ChargerThingHandler) { + bridgeHandler.addHandler(new ChargerReference((String) serial), (ChargerThingHandler) childHandler); + } + } + + @Override + public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) { + Object serial = childThing.getConfiguration().get(Thing.PROPERTY_SERIAL_NUMBER); + if (serial instanceof String && bridgeHandler != null) { + bridgeHandler.removeHandler(new ChargerReference((String) serial)); + } + } + @Override public Collection> getServices() { return Collections.singleton(OcppChargerDiscoveryService.class); diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ChargerReference.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ChargerReference.java new file mode 100644 index 00000000..fb7f3e85 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ChargerReference.java @@ -0,0 +1,37 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +import java.util.Objects; + +public class ChargerReference { + + private final String serial; + + public ChargerReference(String serial) { + this.serial = serial; + } + + public String getSerial() { + return serial; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ChargerReference)) { + return false; + } + return Objects.equals(serial, ((ChargerReference) o).serial); + } + + @Override + public int hashCode() { + return Objects.hashCode(serial); + } + + public String toString() { + return "Charger [SN: " + serial + "]"; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ConfigKeyConstants.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ConfigKeyConstants.java new file mode 100644 index 00000000..bddb0ea5 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/ConfigKeyConstants.java @@ -0,0 +1,14 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +public interface ConfigKeyConstants { + + // 4 + String NUMBER_OF_CONNECTORS = "numberOfConnectors"; + // Core,LocalAuthListManagement,RemoteTrigger,SoC + String SUPPORTED_FEATURE_PROFILES = "supportedFeatureProfiles"; + // 60 + String HEARTBEAT_INTERVAL = "heartbeatInterval"; + // 60 + String METER_VALUE_INTERVAL = "meterValueInterval"; + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/CoreEventHandlerWrapper.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/CoreEventHandlerWrapper.java new file mode 100644 index 00000000..8a10f4f8 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/CoreEventHandlerWrapper.java @@ -0,0 +1,86 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; +import eu.chargetime.ocpp.model.Confirmation; +import eu.chargetime.ocpp.model.Request; +import eu.chargetime.ocpp.model.core.AuthorizeConfirmation; +import eu.chargetime.ocpp.model.core.AuthorizeRequest; +import eu.chargetime.ocpp.model.core.BootNotificationConfirmation; +import eu.chargetime.ocpp.model.core.BootNotificationRequest; +import eu.chargetime.ocpp.model.core.DataTransferConfirmation; +import eu.chargetime.ocpp.model.core.DataTransferRequest; +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.util.Deque; +import java.util.List; +import java.util.UUID; +import java.util.function.Function; + +public class CoreEventHandlerWrapper implements ServerCoreEventHandler { + + private final Deque handlers; + + public CoreEventHandlerWrapper(Deque handlers) { + this.handlers = handlers; + } + + @Override + public AuthorizeConfirmation handleAuthorizeRequest(UUID sessionIndex, AuthorizeRequest request) { + return process(handler -> handler.handleAuthorizeRequest(sessionIndex, request)); + } + + @Override + public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { + return process(handler -> handler.handleBootNotificationRequest(sessionIndex, request)); + } + + @Override + public DataTransferConfirmation handleDataTransferRequest(UUID sessionIndex, DataTransferRequest request) { + return process(handler -> handler.handleDataTransferRequest(sessionIndex, request)); + } + + @Override + public HeartbeatConfirmation handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) { + return process(handler -> handler.handleHeartbeatRequest(sessionIndex, request)); + } + + @Override + public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, MeterValuesRequest request) { + return process(handler -> handler.handleMeterValuesRequest(sessionIndex, request)); + } + + @Override + public StartTransactionConfirmation handleStartTransactionRequest(UUID sessionIndex, StartTransactionRequest request) { + return process(handler -> handler.handleStartTransactionRequest(sessionIndex, request)); + } + + @Override + public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessionIndex, StatusNotificationRequest request) { + return process(handler -> handler.handleStatusNotificationRequest(sessionIndex, request)); + } + + @Override + public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { + return process(handler -> handler.handleStopTransactionRequest(sessionIndex, request)); + } + + private C process(Function consumer) { + C confirmation = null; + for (ServerCoreEventHandler handler : handlers) { + C handlerConfirmation = consumer.apply(handler); + if (confirmation == null && handlerConfirmation != null && handlerConfirmation.validate()) { + confirmation = handlerConfirmation; + } + } + return confirmation; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerConfigRegistry.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerConfigRegistry.java new file mode 100644 index 00000000..661784d7 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerConfigRegistry.java @@ -0,0 +1,9 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +import java.util.Map; + +public interface OcppChargerConfigRegistry { + + Map getConfig(ChargerReference reference); + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerSessionRegistry.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerSessionRegistry.java new file mode 100644 index 00000000..03d4bb47 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppChargerSessionRegistry.java @@ -0,0 +1,12 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +import java.util.UUID; + +public interface OcppChargerSessionRegistry { + + UUID getSession(ChargerReference chargerReference); + + ChargerReference removeSession(UUID session); + + ChargerReference getCharger(UUID sessionIndex); +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppMeasurementMapping.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppMeasurementMapping.java new file mode 100644 index 00000000..b685cab7 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppMeasurementMapping.java @@ -0,0 +1,45 @@ +package org.connectorio.addons.binding.ocpp.internal.server; + +import static java.util.Map.entry; + +import java.util.Map; +import org.connectorio.addons.binding.ocpp.OcppBindingConstants; +import org.connectorio.addons.binding.ocpp.OcppBindingConstants.ChannelRef; +import org.openhab.core.thing.UID; + +public class OcppMeasurementMapping { + + private final static Map MAPPING = Map.ofEntries( + entry("Current.Export", OcppBindingConstants.CURRENT_EXPORT), + entry("Current.Import", OcppBindingConstants.CURRENT_IMPORT), + entry("Current.Offered", OcppBindingConstants.CURRENT_OFFERED), + entry("Energy.Active.Export.Register", OcppBindingConstants.ENERGY_ACTIVE_EXPORT), + entry("Energy.Active.Import.Register", OcppBindingConstants.ENERGY_ACTIVE_IMPORT), + entry("Energy.Reactive.Export.Register", OcppBindingConstants.ENERGY_REACTIVE_EXPORT), + entry("Energy.Reactive.Import.Register", OcppBindingConstants.ENERGY_REACTIVE_IMPORT), + entry("Energy.Active.Export.Interval", OcppBindingConstants.ENERGY_ACTIVE_EXPORT_INTERVAL), + entry("Energy.Active.Import.Interval", OcppBindingConstants.ENERGY_ACTIVE_IMPORT_INTERVAL), + entry("Energy.Reactive.Export.Interval", OcppBindingConstants.ENERGY_REACTIVE_EXPORT_INTERVAL), + entry("Energy.Reactive.Import.Interval", OcppBindingConstants.ENERGY_REACTIVE_IMPORT_INTERVAL), + entry("Frequency", OcppBindingConstants.FREQUENCY), + entry("Power.Active.Export", OcppBindingConstants.POWER_ACTIVE_EXPORT), + entry("Power.Active.Import", OcppBindingConstants.POWER_ACTIVE_IMPORT), + entry("Power.Factor", OcppBindingConstants.POWER_FACTOR), + entry("Power.Offered", OcppBindingConstants.POWER_OFFERED), + entry("Power.Reactive.Export", OcppBindingConstants.POWER_REACTIVE_EXPORT), + entry("Power.Reactive.Import", OcppBindingConstants.POWER_REACTIVE_IMPORT), + entry("RPM", OcppBindingConstants.RPM), + entry("SoC", OcppBindingConstants.SOC), + entry("Temperature", OcppBindingConstants.TEMPERATURE), + entry("Voltage", OcppBindingConstants.VOLTAGE) + ); + + public static UID get(String measurement) { + if (MAPPING.containsKey(measurement)) { + return MAPPING.get(measurement); + } + + return null; + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServer.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServer.java index fc1ade1f..ae396fc0 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServer.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServer.java @@ -17,6 +17,7 @@ */ package org.connectorio.addons.binding.ocpp.internal.server; +import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; import eu.chargetime.ocpp.JSONServer; import eu.chargetime.ocpp.NotConnectedException; import eu.chargetime.ocpp.OccurenceConstraintException; @@ -26,12 +27,21 @@ import eu.chargetime.ocpp.model.Confirmation; import eu.chargetime.ocpp.model.Request; import eu.chargetime.ocpp.model.SessionInformation; +import java.util.Arrays; import java.util.Collections; -import java.util.Set; +import java.util.Deque; +import java.util.LinkedList; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.connectorio.addons.binding.ocpp.internal.OcppRequestListener; import org.connectorio.addons.binding.ocpp.internal.OcppSender; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.BootConfigAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.HearbeatAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.AuthorizationIdTagAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.BootRegistrationAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.RequestListenerAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.StatusAdapter; +import org.connectorio.addons.binding.ocpp.internal.server.adapter.TransactionAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,12 +51,16 @@ public class OcppServer implements OcppSender { private final JSONServer server; private final String ip; private final int port; + private final OcppChargerSessionRegistry chargerSessionRegistry; - public OcppServer(String ip, int port, OcppRequestListener listener, Set identifiers, Set tags) { + public OcppServer(String ip, int port, OcppChargerSessionRegistry chargerSessionRegistry, + Deque eventHandlers) { this.ip = ip; this.port = port; - OcppServerCoreEventHandler eventHandler = new OcppServerCoreEventHandler(this, listener, identifiers, tags); - this.server = new JSONServer(new ServerCoreProfile(eventHandler)); + this.chargerSessionRegistry = chargerSessionRegistry; + + CoreEventHandlerWrapper handler = new CoreEventHandlerWrapper(eventHandlers); + this.server = new JSONServer(new ServerCoreProfile(handler)); } public void activate() { @@ -59,19 +73,21 @@ public void newSession(UUID sessionIndex, SessionInformation information) { @Override public void lostSession(UUID sessionIndex) { logger.info("Terminated connection {}.", sessionIndex); + chargerSessionRegistry.removeSession(sessionIndex); } }); } @Override - public CompletionStage send(UUID sessionIndex, Request request) { + public CompletionStage send(ChargerReference chargerReference, Request request) { try { + UUID sessionIndex = chargerSessionRegistry.getSession(chargerReference); + if (sessionIndex == null) { + logger.warn("Could not send request {} to charger {}. Session not found.", request, chargerReference); + return CompletableFuture.failedFuture(new NotConnectedException()); + } return this.server.send(sessionIndex, request); - } catch (OccurenceConstraintException e) { - throw new RuntimeException(e); - } catch (UnsupportedFeatureException e) { - throw new RuntimeException(e); - } catch (NotConnectedException e) { + } catch (OccurenceConstraintException | UnsupportedFeatureException | NotConnectedException e) { throw new RuntimeException(e); } } @@ -82,9 +98,4 @@ public void close() { } } - public static void main(String[] args) { - OcppServer ocppServer = new OcppServer("127.0.0.1", 8888, null, Collections.emptySet(), Collections.emptySet()); - ocppServer.activate(); - } - } diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/AuthorizationIdTagAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/AuthorizationIdTagAdapter.java new file mode 100644 index 00000000..1448c144 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/AuthorizationIdTagAdapter.java @@ -0,0 +1,29 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.AuthorizationStatus; +import eu.chargetime.ocpp.model.core.AuthorizeConfirmation; +import eu.chargetime.ocpp.model.core.AuthorizeRequest; +import eu.chargetime.ocpp.model.core.IdTagInfo; +import java.util.Set; +import java.util.UUID; + +public class AuthorizationIdTagAdapter extends CoreEventHandlerAdapter { + + private final Set tags; + + public AuthorizationIdTagAdapter(Set tags) { + this.tags = tags; + } + + @Override + public AuthorizeConfirmation handleAuthorizeRequest(UUID sessionIndex, AuthorizeRequest request) { + String tag = request.getIdTag(); + + if (tags.isEmpty() || tags.contains(tag)) { + return new AuthorizeConfirmation(new IdTagInfo(AuthorizationStatus.Accepted)); + } + + return new AuthorizeConfirmation(new IdTagInfo(AuthorizationStatus.Invalid)); + } + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootConfigAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootConfigAdapter.java new file mode 100644 index 00000000..b91f8dba --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootConfigAdapter.java @@ -0,0 +1,57 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.BootNotificationConfirmation; +import eu.chargetime.ocpp.model.core.BootNotificationRequest; +import eu.chargetime.ocpp.model.core.GetConfigurationConfirmation; +import eu.chargetime.ocpp.model.core.GetConfigurationRequest; +import eu.chargetime.ocpp.model.core.KeyValueType; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.connectorio.addons.binding.ocpp.internal.OcppSender; +import org.connectorio.addons.binding.ocpp.internal.server.ChargerReference; +import org.connectorio.addons.binding.ocpp.internal.server.OcppChargerConfigRegistry; +import org.connectorio.addons.binding.ocpp.internal.server.OcppChargerSessionRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BootConfigAdapter extends CoreEventHandlerAdapter implements OcppChargerConfigRegistry { + + private final Logger logger = LoggerFactory.getLogger(BootConfigAdapter.class); + private final Map> configMap = new ConcurrentHashMap<>(); + private final OcppChargerSessionRegistry sessionRegistry; + private final OcppSender sender; + + public BootConfigAdapter(OcppChargerSessionRegistry sessionRegistry, OcppSender sender) { + this.sessionRegistry = sessionRegistry; + this.sender = sender; + } + + @Override + public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { + ChargerReference reference = new ChargerReference(request.getChargePointSerialNumber()); + if (sessionRegistry.getSession(reference) != null) { + sender.send(reference, new GetConfigurationRequest()).whenComplete((r, e) -> { + if (e != null) { + logger.warn("Could not obtain configuration for charger {}. This indicates incomplete implementation of OCPP core profile for charger.", reference, e); + return; + } + + Map config = new LinkedHashMap<>(); + KeyValueType[] keys = r.getConfigurationKey(); + for (KeyValueType k : keys) { + config.put(k.getKey(), k.getValue()); + } + configMap.put(reference, config); + }); + } + + return null; + } + + @Override + public Map getConfig(ChargerReference reference) { + return configMap.get(reference); + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootRegistrationAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootRegistrationAdapter.java new file mode 100644 index 00000000..4c7d69c0 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/BootRegistrationAdapter.java @@ -0,0 +1,56 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.BootNotificationConfirmation; +import eu.chargetime.ocpp.model.core.BootNotificationRequest; +import eu.chargetime.ocpp.model.core.RegistrationStatus; +import java.time.ZonedDateTime; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.connectorio.addons.binding.ocpp.internal.server.ChargerReference; +import org.connectorio.addons.binding.ocpp.internal.server.OcppChargerSessionRegistry; + +public class BootRegistrationAdapter extends CoreEventHandlerAdapter implements + OcppChargerSessionRegistry { + + private final Map registrations = new ConcurrentHashMap<>(); + + private final Set identifiers; + + public BootRegistrationAdapter(Set identifiers) { + this.identifiers = identifiers; + } + + @Override + public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { + ZonedDateTime time = ZonedDateTime.now(); + if (identifiers.isEmpty() || identifiers.contains(request.getChargePointSerialNumber())) { + registrations.put(sessionIndex, new ChargerReference(request.getChargePointSerialNumber())); + return new BootNotificationConfirmation(time, 60, RegistrationStatus.Accepted); + } + + // keep charger connected, but not active + return new BootNotificationConfirmation(time, 300, RegistrationStatus.Pending); + } + + @Override + public UUID getSession(ChargerReference chargerReference) { + for (Map.Entry entry : registrations.entrySet()) { + if (entry.getValue().equals(chargerReference)) { + return entry.getKey(); + } + } + return null; + } + + @Override + public ChargerReference removeSession(UUID session) { + return registrations.remove(session); + } + + @Override + public ChargerReference getCharger(UUID sessionIndex) { + return registrations.get(sessionIndex); + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/CoreEventHandlerAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/CoreEventHandlerAdapter.java new file mode 100644 index 00000000..0183e215 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/CoreEventHandlerAdapter.java @@ -0,0 +1,63 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; +import eu.chargetime.ocpp.model.core.AuthorizeConfirmation; +import eu.chargetime.ocpp.model.core.AuthorizeRequest; +import eu.chargetime.ocpp.model.core.BootNotificationConfirmation; +import eu.chargetime.ocpp.model.core.BootNotificationRequest; +import eu.chargetime.ocpp.model.core.DataTransferConfirmation; +import eu.chargetime.ocpp.model.core.DataTransferRequest; +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.util.UUID; + +public class CoreEventHandlerAdapter implements ServerCoreEventHandler { + + @Override + public AuthorizeConfirmation handleAuthorizeRequest(UUID sessionIndex, AuthorizeRequest request) { + return null; + } + + @Override + public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { + return null; + } + + @Override + public DataTransferConfirmation handleDataTransferRequest(UUID sessionIndex, DataTransferRequest request) { + return null; + } + + @Override + public HeartbeatConfirmation handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) { + return null; + } + + @Override + public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, MeterValuesRequest request) { + return null; + } + + @Override + public StartTransactionConfirmation handleStartTransactionRequest(UUID sessionIndex, StartTransactionRequest request) { + return null; + } + + @Override + public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessionIndex, StatusNotificationRequest request) { + return null; + } + + @Override + public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { + return null; + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/HearbeatAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/HearbeatAdapter.java new file mode 100644 index 00000000..16ad9321 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/HearbeatAdapter.java @@ -0,0 +1,15 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.HeartbeatConfirmation; +import eu.chargetime.ocpp.model.core.HeartbeatRequest; +import java.time.ZonedDateTime; +import java.util.UUID; + +public class HearbeatAdapter extends CoreEventHandlerAdapter { + + @Override + public HeartbeatConfirmation handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) { + //System.out.println(request); + return new HeartbeatConfirmation(ZonedDateTime.now()); + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServerCoreEventHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/RequestListenerAdapter.java similarity index 50% rename from bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServerCoreEventHandler.java rename to bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/RequestListenerAdapter.java index 16ed9d2e..ca2534fe 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/OcppServerCoreEventHandler.java +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/RequestListenerAdapter.java @@ -1,21 +1,4 @@ -/* - * Copyright (C) 2022-2022 ConnectorIO Sp. z o.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.connectorio.addons.binding.ocpp.internal.server; +package org.connectorio.addons.binding.ocpp.internal.server.adapter; import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; import eu.chargetime.ocpp.model.Request; @@ -29,85 +12,68 @@ 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.RegistrationStatus; 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.Set; import java.util.UUID; import org.connectorio.addons.binding.ocpp.internal.OcppRequestListener; -import org.connectorio.addons.binding.ocpp.internal.OcppSender; -import org.eclipse.jetty.client.api.Request.RequestListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public class OcppServerCoreEventHandler implements ServerCoreEventHandler { - private final Logger logger = LoggerFactory.getLogger(OcppServerCoreEventHandler.class); - private OcppSender sender; - private OcppRequestListener listener; - private final Set identifiers; - private final Set tags; +public class RequestListenerAdapter implements ServerCoreEventHandler { - public OcppServerCoreEventHandler(OcppSender sender, OcppRequestListener listener, Set identifiers, Set tags) { - this.sender = sender; + private final OcppRequestListener listener; + + public RequestListenerAdapter(OcppRequestListener listener) { this.listener = listener; - this.identifiers = identifiers; - this.tags = tags; } @Override public AuthorizeConfirmation handleAuthorizeRequest(UUID sessionIndex, AuthorizeRequest request) { - request.getIdTag(); + listener.onRequest(request); return null; } @Override public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { - if (identifiers.isEmpty()) { - listener.onRequest(request); - return new BootNotificationConfirmation(ZonedDateTime.now(), 1000, RegistrationStatus.Accepted); - } - if (identifiers.contains(request.getMeterSerialNumber())) { - listener.onRequest(request); - return new BootNotificationConfirmation(ZonedDateTime.now(), 1000, RegistrationStatus.Accepted); - } - - // skip notifying listeners - return new BootNotificationConfirmation(ZonedDateTime.now(), 1000, RegistrationStatus.Rejected); + listener.onRequest(request); + return null; } @Override public DataTransferConfirmation handleDataTransferRequest(UUID sessionIndex, DataTransferRequest request) { + listener.onRequest(request); return null; } @Override public HeartbeatConfirmation handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) { - return new HeartbeatConfirmation(ZonedDateTime.now()); + listener.onRequest(request); + return null; } @Override public MeterValuesConfirmation handleMeterValuesRequest(UUID sessionIndex, MeterValuesRequest request) { - logger.info("Received meter values for session {}: {}", sessionIndex, request); - return new MeterValuesConfirmation(); + listener.onRequest(request); + return null; } @Override public StartTransactionConfirmation handleStartTransactionRequest(UUID sessionIndex, StartTransactionRequest request) { + listener.onRequest(request); return null; } @Override public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessionIndex, StatusNotificationRequest request) { - return new StatusNotificationConfirmation(); + listener.onRequest(request); + return null; } @Override public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { + listener.onRequest(request); return null; } } diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/StatusAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/StatusAdapter.java new file mode 100644 index 00000000..67793637 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/StatusAdapter.java @@ -0,0 +1,17 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.StatusNotificationConfirmation; +import eu.chargetime.ocpp.model.core.StatusNotificationRequest; +import java.util.UUID; + +public class StatusAdapter extends CoreEventHandlerAdapter { + + @Override + public StatusNotificationConfirmation handleStatusNotificationRequest(UUID sessionIndex, StatusNotificationRequest request) { + // return super.handleStatusNotificationRequest(sessionIndex, request); + + System.out.println("Status " + request); + + return new StatusNotificationConfirmation(); + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/TransactionAdapter.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/TransactionAdapter.java new file mode 100644 index 00000000..f355c27f --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/adapter/TransactionAdapter.java @@ -0,0 +1,24 @@ +package org.connectorio.addons.binding.ocpp.internal.server.adapter; + +import eu.chargetime.ocpp.model.core.StartTransactionConfirmation; +import eu.chargetime.ocpp.model.core.StartTransactionRequest; +import eu.chargetime.ocpp.model.core.StopTransactionConfirmation; +import eu.chargetime.ocpp.model.core.StopTransactionRequest; +import java.util.UUID; + +public class TransactionAdapter extends CoreEventHandlerAdapter { + + @Override + public StartTransactionConfirmation handleStartTransactionRequest(UUID sessionIndex, StartTransactionRequest request) { + // return super.handleStartTransactionRequest(sessionIndex, request); + System.out.println("Start transaction " + request); + return new StartTransactionConfirmation(); + } + + @Override + public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { + //return super.handleStopTransactionRequest(sessionIndex, request); + System.out.println("Stop transaction " + request); + return new StopTransactionConfirmation(); + } +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/HeartbeatHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/HeartbeatHandler.java new file mode 100644 index 00000000..53f8694e --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/HeartbeatHandler.java @@ -0,0 +1,10 @@ +package org.connectorio.addons.binding.ocpp.internal.server.listener; + +import eu.chargetime.ocpp.model.core.HeartbeatConfirmation; +import eu.chargetime.ocpp.model.core.HeartbeatRequest; + +public interface HeartbeatHandler { + + HeartbeatConfirmation handleHeartbeat(HeartbeatRequest request); + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/MeterValuesHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/MeterValuesHandler.java new file mode 100644 index 00000000..dbf4c908 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/MeterValuesHandler.java @@ -0,0 +1,10 @@ +package org.connectorio.addons.binding.ocpp.internal.server.listener; + +import eu.chargetime.ocpp.model.core.MeterValuesConfirmation; +import eu.chargetime.ocpp.model.core.MeterValuesRequest; + +public interface MeterValuesHandler { + + MeterValuesConfirmation handleMeterValues(MeterValuesRequest request); + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/StatusNotificationHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/StatusNotificationHandler.java new file mode 100644 index 00000000..1a3d689b --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/StatusNotificationHandler.java @@ -0,0 +1,10 @@ +package org.connectorio.addons.binding.ocpp.internal.server.listener; + +import eu.chargetime.ocpp.model.core.StatusNotificationConfirmation; +import eu.chargetime.ocpp.model.core.StatusNotificationRequest; + +public interface StatusNotificationHandler { + + StatusNotificationConfirmation handleStatusNotification(StatusNotificationRequest request); + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/TransactionHandler.java b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/TransactionHandler.java new file mode 100644 index 00000000..05d09ff3 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/java/org/connectorio/addons/binding/ocpp/internal/server/listener/TransactionHandler.java @@ -0,0 +1,13 @@ +package org.connectorio.addons.binding.ocpp.internal.server.listener; + +import eu.chargetime.ocpp.model.core.StartTransactionConfirmation; +import eu.chargetime.ocpp.model.core.StartTransactionRequest; +import eu.chargetime.ocpp.model.core.StopTransactionConfirmation; +import eu.chargetime.ocpp.model.core.StopTransactionRequest; + +public interface TransactionHandler { + + StartTransactionConfirmation handleStartTransaction(StartTransactionRequest request); + StopTransactionConfirmation handleStopTransaction(StopTransactionRequest request); + +} diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/channels.xml new file mode 100644 index 00000000..bbc4d292 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/channels.xml @@ -0,0 +1,108 @@ + + + + + + + DateTime + + Date time value. + + + + Number + + Number value. + + + + String + + String value. + + + + + Number:ElectricCurrent + + Electric current value. + + + + Number:Energy + + Energy. + + + + Number:Frequency + + Frequency. + + + + Dimmer + + + + + Number:Power + + Power. + + + + Number:Temperature + + Temperature. + + + + Number:ElectricPotential + + Electric voltage value. + + + + + String + + + + + + + + + + + + + + + + + diff --git a/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/thing-types.xml index 13657762..86dbd650 100644 --- a/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.connectorio.addons.binding.ocpp/src/main/resources/OH-INF/thing/thing-types.xml @@ -62,7 +62,7 @@ - + @@ -71,6 +71,10 @@ An instance of electric charger. + + + Serial number of charge point (defined by manufacturer). + @@ -80,7 +84,7 @@ s - + @@ -89,6 +93,134 @@ A charger connector. + + + + + + Current transaction. + + + + Tag identifier. + + + + Start timestamp of most recent transaction. + + + + Stop timestamp of most recent transaction. + + + + Value of meter energy reading at the start of transaction. + + + + Value of meter energy reading at the end of transaction. + + + + + + + + Instantaneous current flow from EV + + + + Instantaneous current flow to EV + + + + Maximum current offered to EV + + + + Energy exported by EV (Wh or kWh) + + + + Energy imported by EV (Wh or kWh) + + + + Reactive energy exported by EV (varh or kvarh) + + + + Reactive energy imported by EV (varh or kvarh) + + + + Energy exported by EV (Wh or kWh) + + + + Energy imported by EV (Wh or kWh) + + + + Reactive energy exported by EV. (varh or kvarh) + + + + Reactive energy imported by EV. (varh or kvarh) + + + + Instantaneous reading of powerline frequency + + + + Instantaneous active power exported by EV. (W or kW) + + + + Instantaneous active power imported by EV. (W or kW) + + + + Instantaneous power factor of total energy flow + + + + Maximum power offered to EV + + + + Instantaneous reactive power exported by EV. (var or kvar) + + + + Instantaneous reactive power imported by EV. (var or kvar) + + + + Fan speed in RPM + + + + State of charge of charging vehicle in percentage. + + + + Temperature reading inside Charge Point. + + + + Instantaneous AC RMS supply voltage + + + + + + + Identifier of connector - starts from 1. + + +