Search in sources :

Example 1 with StringPredicate

use of org.openremote.model.query.filter.StringPredicate in project openremote by openremote.

the class EnergyOptimisationService method runOptimisation.

/**
 * Runs the optimisation routine for the specified time; it is important that this method does not throw an
 * exception as it will cancel the scheduled task thus stopping future optimisations.
 */
protected void runOptimisation(String optimisationAssetId, Instant optimisationTime) {
    OptimisationInstance optimisationInstance = assetOptimisationInstanceMap.get(optimisationAssetId);
    if (optimisationInstance == null) {
        return;
    }
    LOG.finer(getLogPrefix(optimisationAssetId) + "Running for time '" + formatter.format(optimisationTime));
    EnergyOptimiser optimiser = optimisationInstance.energyOptimiser;
    int intervalCount = optimiser.get24HourIntervalCount();
    double intervalSize = optimiser.getIntervalSize();
    LOG.finest(getLogPrefix(optimisationAssetId) + "Fetching child assets of type '" + ElectricitySupplierAsset.class.getSimpleName() + "'");
    List<ElectricitySupplierAsset> supplierAssets = assetStorageService.findAll(new AssetQuery().types(ElectricitySupplierAsset.class).recursive(true).parents(optimisationAssetId)).stream().filter(asset -> asset.hasAttribute(ElectricitySupplierAsset.TARIFF_IMPORT)).map(asset -> (ElectricitySupplierAsset) asset).collect(Collectors.toList());
    if (supplierAssets.size() != 1) {
        LOG.warning(getLogPrefix(optimisationAssetId) + "Expected exactly one " + ElectricitySupplierAsset.class.getSimpleName() + " asset with a '" + ElectricitySupplierAsset.TARIFF_IMPORT.getName() + "' attribute but found: " + supplierAssets.size());
        return;
    }
    double[] powerNets = new double[intervalCount];
    ElectricitySupplierAsset supplierAsset = supplierAssets.get(0);
    if (LOG.isLoggable(Level.FINEST)) {
        LOG.finest(getLogPrefix(optimisationAssetId) + "Found child asset of type '" + ElectricitySupplierAsset.class.getSimpleName() + "': " + supplierAsset);
    }
    // Do some basic validation
    if (supplierAsset.getTariffImport().isPresent()) {
        LOG.warning(getLogPrefix(optimisationAssetId) + ElectricitySupplierAsset.class.getSimpleName() + " asset '" + ElectricitySupplierAsset.TARIFF_IMPORT.getName() + "' attribute has no value");
    }
    LOG.finest(getLogPrefix(optimisationAssetId) + "Fetching optimisable child assets of type '" + ElectricityStorageAsset.class.getSimpleName() + "'");
    List<ElectricityStorageAsset> optimisableStorageAssets = assetStorageService.findAll(new AssetQuery().recursive(true).parents(optimisationAssetId).types(ElectricityStorageAsset.class).attributes(new LogicGroup<>(LogicGroup.Operator.AND, Collections.singletonList(new LogicGroup<>(LogicGroup.Operator.OR, new AttributePredicate(ElectricityStorageAsset.SUPPORTS_IMPORT.getName(), new BooleanPredicate(true)), new AttributePredicate(ElectricityStorageAsset.SUPPORTS_EXPORT.getName(), new BooleanPredicate(true)))), new AttributePredicate().name(new StringPredicate(ElectricityAsset.POWER_SETPOINT.getName()))))).stream().map(asset -> (ElectricityStorageAsset) asset).collect(Collectors.toList());
    List<ElectricityStorageAsset> finalOptimisableStorageAssets = optimisableStorageAssets;
    optimisableStorageAssets = optimisableStorageAssets.stream().filter(asset -> {
        // Exclude force charged assets (so we don't mess with the setpoint)
        if (forceChargeAssetIds.contains(asset.getId())) {
            LOG.finest("Optimisable asset was requested to force charge so it won't be optimised: " + asset.getId());
            @SuppressWarnings("OptionalGetWithoutIsPresent") Attribute<Double> powerAttribute = asset.getAttribute(ElectricityAsset.POWER).get();
            double[] powerLevels = get24HAttributeValues(asset.getId(), powerAttribute, optimiser.getIntervalSize(), intervalCount, optimisationTime);
            IntStream.range(0, intervalCount).forEach(i -> powerNets[i] += powerLevels[i]);
            double currentEnergyLevel = asset.getEnergyLevel().orElse(0d);
            double maxEnergyLevel = getElectricityStorageAssetEnergyLevelMax(asset);
            if (currentEnergyLevel >= maxEnergyLevel) {
                LOG.info("Force charged asset has reached maxEnergyLevelPercentage so stopping charging: " + asset.getId());
                forceChargeAssetIds.remove(asset.getId());
                assetProcessingService.sendAttributeEvent(new AttributeEvent(asset.getId(), ElectricityStorageAsset.POWER_SETPOINT, 0d));
                assetProcessingService.sendAttributeEvent(new AttributeEvent(asset.getId(), ElectricityStorageAsset.FORCE_CHARGE, AttributeExecuteStatus.COMPLETED));
            }
            return false;
        }
        if (asset instanceof ElectricityChargerAsset) {
            // Check if it has a child vehicle asset
            return finalOptimisableStorageAssets.stream().noneMatch(a -> {
                if (a instanceof ElectricVehicleAsset && a.getParentId().equals(asset.getId())) {
                    // Take the lowest power max from vehicle or charger
                    double vehiclePowerImportMax = a.getPowerImportMax().orElse(Double.MAX_VALUE);
                    double vehiclePowerExportMax = a.getPowerExportMax().orElse(Double.MAX_VALUE);
                    double chargerPowerImportMax = asset.getPowerImportMax().orElse(Double.MAX_VALUE);
                    double chargerPowerExportMax = asset.getPowerExportMax().orElse(Double.MAX_VALUE);
                    double smallestPowerImportMax = Math.min(vehiclePowerImportMax, chargerPowerImportMax);
                    double smallestPowerExportMax = Math.min(vehiclePowerExportMax, chargerPowerExportMax);
                    if (smallestPowerImportMax < vehiclePowerImportMax) {
                        LOG.fine("Reducing vehicle power import max due to connected charger limit: vehicle=" + a.getId() + ", oldPowerImportMax=" + vehiclePowerImportMax + ", newPowerImportMax=" + smallestPowerImportMax);
                        a.setPowerImportMax(smallestPowerImportMax);
                    }
                    if (smallestPowerExportMax < vehiclePowerExportMax) {
                        LOG.fine("Reducing vehicle power Export max due to connected charger limit: vehicle=" + a.getId() + ", oldPowerExportMax=" + vehiclePowerExportMax + ", newPowerExportMax=" + smallestPowerExportMax);
                        a.setPowerExportMax(smallestPowerExportMax);
                    }
                    LOG.finest("Excluding charger from optimisable assets and child vehicle will be used instead: " + asset.getId());
                    return true;
                }
                return false;
            });
        }
        return true;
    }).sorted(Comparator.comparingInt(asset -> asset.getEnergyLevelSchedule().map(schedule -> 0).orElse(1))).collect(Collectors.toList());
    if (optimisableStorageAssets.isEmpty()) {
        LOG.warning(getLogPrefix(optimisationAssetId) + "Expected at least one optimisable '" + ElectricityStorageAsset.class.getSimpleName() + " asset with a '" + ElectricityAsset.POWER_SETPOINT.getName() + "' attribute but found none");
        return;
    }
    if (LOG.isLoggable(Level.FINEST)) {
        LOG.finest(getLogPrefix(optimisationAssetId) + "Found optimisable child assets of type '" + ElectricityStorageAsset.class.getSimpleName() + "': " + optimisableStorageAssets.stream().map(Asset::getId).collect(Collectors.joining(", ")));
    }
    LOG.finest(getLogPrefix(optimisationAssetId) + "Fetching plain consumer and producer child assets of type '" + ElectricityProducerAsset.class.getSimpleName() + "', '" + ElectricityConsumerAsset.class.getSimpleName() + "', '" + ElectricityStorageAsset.class.getSimpleName() + "'");
    AtomicInteger count = new AtomicInteger(0);
    assetStorageService.findAll(new AssetQuery().recursive(true).parents(optimisationAssetId).types(ElectricityConsumerAsset.class, ElectricityProducerAsset.class).attributes(new AttributePredicate().name(new StringPredicate(ElectricityAsset.POWER.getName())))).forEach(asset -> {
        @SuppressWarnings("OptionalGetWithoutIsPresent") Attribute<Double> powerAttribute = asset.getAttribute(ElectricityAsset.POWER).get();
        double[] powerLevels = get24HAttributeValues(asset.getId(), powerAttribute, optimiser.getIntervalSize(), intervalCount, optimisationTime);
        IntStream.range(0, intervalCount).forEach(i -> powerNets[i] += powerLevels[i]);
        count.incrementAndGet();
    });
    // Get power of storage assets that don't support neither import or export (treat them as plain consumers/producers)
    List<ElectricityStorageAsset> plainStorageAssets = assetStorageService.findAll(new AssetQuery().recursive(true).parents(optimisationAssetId).types(ElectricityStorageAsset.class).attributes(new AttributePredicate().name(new StringPredicate(ElectricityAsset.POWER.getName())), new AttributePredicate(ElectricityStorageAsset.SUPPORTS_IMPORT.getName(), new BooleanPredicate(true), true, null), new AttributePredicate(ElectricityStorageAsset.SUPPORTS_EXPORT.getName(), new BooleanPredicate(true), true, null))).stream().map(asset -> (ElectricityStorageAsset) asset).collect(Collectors.toList());
    // Exclude chargers with a power value != 0 and a child vehicle with a power value != 0 (avoid double counting - vehicle takes priority)
    plainStorageAssets.stream().filter(asset -> {
        if (asset instanceof ElectricityChargerAsset) {
            // Check if it has a child vehicle asset also check optimisable assets as child vehicle could be in there
            return plainStorageAssets.stream().noneMatch(a -> {
                if (a instanceof ElectricVehicleAsset && a.getParentId().equals(asset.getId())) {
                    LOG.finest("Excluding charger from plain consumer/producer calculations to avoid double counting power: " + asset.getId());
                    return true;
                }
                return false;
            }) && finalOptimisableStorageAssets.stream().noneMatch(a -> {
                if (a instanceof ElectricVehicleAsset && a.getParentId().equals(asset.getId())) {
                    LOG.finest("Excluding charger from plain consumer/producer calculations to avoid double counting power: " + asset.getId());
                    return true;
                }
                return false;
            });
        }
        return true;
    }).forEach(asset -> {
        @SuppressWarnings("OptionalGetWithoutIsPresent") Attribute<Double> powerAttribute = asset.getAttribute(ElectricityAsset.POWER).get();
        double[] powerLevels = get24HAttributeValues(asset.getId(), powerAttribute, optimiser.getIntervalSize(), intervalCount, optimisationTime);
        IntStream.range(0, intervalCount).forEach(i -> powerNets[i] += powerLevels[i]);
        count.incrementAndGet();
    });
    if (LOG.isLoggable(Level.FINER)) {
        LOG.finer(getLogPrefix(optimisationAssetId) + "Found plain consumer and producer child assets count=" + count.get());
        LOG.finer("Calculated net power of consumers and producers: " + Arrays.toString(powerNets));
    }
    // Get supplier costs for each interval
    double financialWeightingImport = optimiser.getFinancialWeighting();
    double financialWeightingExport = optimiser.getFinancialWeighting();
    if (financialWeightingImport < 1d && !supplierAsset.getCarbonImport().isPresent()) {
        financialWeightingImport = 1d;
    }
    if (financialWeightingExport < 1d && !supplierAsset.getCarbonExport().isPresent()) {
        financialWeightingExport = 1d;
    }
    double[] costsImport = get24HAttributeValues(supplierAsset.getId(), supplierAsset.getAttribute(ElectricitySupplierAsset.TARIFF_IMPORT).orElse(null), optimiser.getIntervalSize(), intervalCount, optimisationTime);
    double[] costsExport = get24HAttributeValues(supplierAsset.getId(), supplierAsset.getAttribute(ElectricitySupplierAsset.TARIFF_EXPORT).orElse(null), optimiser.getIntervalSize(), intervalCount, optimisationTime);
    if (financialWeightingImport < 1d || financialWeightingExport < 1d) {
        double[] carbonImport = get24HAttributeValues(supplierAsset.getId(), supplierAsset.getAttribute(ElectricitySupplierAsset.CARBON_IMPORT).orElse(null), optimiser.getIntervalSize(), intervalCount, optimisationTime);
        double[] carbonExport = get24HAttributeValues(supplierAsset.getId(), supplierAsset.getAttribute(ElectricitySupplierAsset.CARBON_EXPORT).orElse(null), optimiser.getIntervalSize(), intervalCount, optimisationTime);
        LOG.finer(getLogPrefix(optimisationAssetId) + "Adjusting costs to include some carbon weighting, financialWeightingImport=" + financialWeightingImport + ", financialWeightingExport=" + financialWeightingExport);
        for (int i = 0; i < costsImport.length; i++) {
            costsImport[i] = (financialWeightingImport * costsImport[i]) + ((1 - financialWeightingImport) * carbonImport[i]);
            costsExport[i] = (financialWeightingExport * costsExport[i]) + ((1 - financialWeightingExport) * carbonExport[i]);
        }
    }
    if (LOG.isLoggable(Level.FINER)) {
        LOG.finer(getLogPrefix(optimisationAssetId) + "Import costs: " + Arrays.toString(costsImport));
        LOG.finer(getLogPrefix(optimisationAssetId) + "Export costs: " + Arrays.toString(costsExport));
    }
    // Savings variables
    List<String> obsoleteUnoptimisedAssetIds = new ArrayList<>(optimisationInstance.unoptimisedStorageAssetEnergyLevels.keySet());
    double unoptimisedPower = powerNets[0];
    double financialCost = 0d;
    double carbonCost = 0d;
    double unoptimisedFinancialCost = 0d;
    double unoptimisedCarbonCost = 0d;
    // Optimise storage assets with priority on storage assets with an energy schedule (already sorted above)
    double importPowerMax = supplierAsset.getPowerImportMax().orElse(Double.MAX_VALUE);
    double exportPowerMax = -1 * supplierAsset.getPowerExportMax().orElse(Double.MAX_VALUE);
    double[] importPowerMaxes = new double[intervalCount];
    double[] exportPowerMaxes = new double[intervalCount];
    Arrays.fill(importPowerMaxes, importPowerMax);
    Arrays.fill(exportPowerMaxes, exportPowerMax);
    long periodSeconds = (long) (optimiser.getIntervalSize() * 60 * 60);
    for (ElectricityStorageAsset storageAsset : optimisableStorageAssets) {
        boolean hasSetpoint = storageAsset.hasAttribute(ElectricityStorageAsset.POWER_SETPOINT);
        boolean supportsExport = storageAsset.isSupportsExport().orElse(false);
        boolean supportsImport = storageAsset.isSupportsImport().orElse(false);
        LOG.finer(getLogPrefix(optimisationAssetId) + "Optimising power set points for storage asset: " + storageAsset);
        if (!supportsExport && !supportsImport) {
            LOG.finest(getLogPrefix(optimisationAssetId) + "Storage asset doesn't support import or export: " + storageAsset.getId());
            continue;
        }
        if (!hasSetpoint) {
            LOG.info(getLogPrefix(optimisationAssetId) + "Storage asset has no '" + ElectricityStorageAsset.POWER_SETPOINT.getName() + "' attribute so cannot be controlled: " + storageAsset.getId());
            continue;
        }
        double energyCapacity = storageAsset.getEnergyCapacity().orElse(0d);
        double energyLevel = Math.min(energyCapacity, storageAsset.getEnergyLevel().orElse(-1d));
        if (energyCapacity <= 0d || energyLevel < 0) {
            LOG.info(getLogPrefix(optimisationAssetId) + "Storage asset has no capacity or energy level so cannot import or export energy: " + storageAsset.getId());
            continue;
        }
        double energyLevelMax = Math.min(energyCapacity, ((double) storageAsset.getEnergyLevelPercentageMax().orElse(100) / 100) * energyCapacity);
        double energyLevelMin = Math.min(energyCapacity, ((double) storageAsset.getEnergyLevelPercentageMin().orElse(0) / 100) * energyCapacity);
        double[] energyLevelMins = new double[intervalCount];
        double[] energyLevelMaxs = new double[intervalCount];
        Arrays.fill(energyLevelMins, energyLevelMin);
        Arrays.fill(energyLevelMaxs, energyLevelMax);
        // Does the storage support import and have an energy level schedule
        Optional<Integer[][]> energyLevelScheduleOptional = storageAsset.getEnergyLevelSchedule();
        boolean hasEnergyMinRequirement = energyLevelMin > 0 || energyLevelScheduleOptional.isPresent();
        double powerExportMax = storageAsset.getPowerExportMax().map(power -> -1 * power).orElse(Double.MIN_VALUE);
        double powerImportMax = storageAsset.getPowerImportMax().orElse(Double.MAX_VALUE);
        int[][] energySchedule = energyLevelScheduleOptional.map(dayArr -> Arrays.stream(dayArr).map(hourArr -> Arrays.stream(hourArr).mapToInt(i -> i != null ? i : 0).toArray()).toArray(int[][]::new)).orElse(null);
        if (energySchedule != null) {
            LOG.finer(getLogPrefix(optimisationAssetId) + "Applying energy schedule for storage asset: " + storageAsset.getId());
            optimiser.applyEnergySchedule(energyLevelMins, energyLevelMaxs, energyCapacity, energySchedule, LocalDateTime.ofInstant(Instant.ofEpochMilli(timerService.getCurrentTimeMillis()), ZoneId.systemDefault()));
        }
        double maxEnergyLevelMin = Arrays.stream(energyLevelMins).max().orElse(0);
        boolean isConnected = storageAssetConnected(storageAsset);
        // TODO: Make these a function of energy level
        Function<Integer, Double> powerImportMaxCalculator = interval -> interval == 0 && !isConnected ? 0 : powerImportMax;
        Function<Integer, Double> powerExportMaxCalculator = interval -> interval == 0 && !isConnected ? 0 : powerExportMax;
        if (hasEnergyMinRequirement) {
            LOG.finer(getLogPrefix(optimisationAssetId) + "Normalising min energy requirements for storage asset: " + storageAsset.getId());
            optimiser.normaliseEnergyMinRequirements(energyLevelMins, powerImportMaxCalculator, powerExportMaxCalculator, energyLevel);
            if (LOG.isLoggable(Level.FINEST)) {
                LOG.finest(getLogPrefix(optimisationAssetId) + "Min energy requirements for storage asset '" + storageAsset.getId() + "': " + Arrays.toString(energyLevelMins));
            }
        }
        // Calculate the power setpoints for this asset and update power net values for each interval
        double[] setpoints = getStoragePowerSetpoints(optimisationInstance, storageAsset, energyLevelMins, energyLevelMaxs, powerNets, importPowerMaxes, exportPowerMaxes, costsImport, costsExport);
        if (setpoints != null) {
            // Assume these setpoints will be applied so update the power net values with these
            for (int i = 0; i < powerNets.length; i++) {
                if (i == 0) {
                    if (!storageAssetConnected(storageAsset)) {
                        LOG.finer("Optimised storage asset not connected so interval 0 will not be counted or actioned: " + storageAsset.getId());
                        setpoints[i] = 0;
                        continue;
                    }
                    // Update savings/cost data with costs specific to this asset
                    if (setpoints[i] > 0) {
                        financialCost += storageAsset.getTariffImport().orElse(0d) * setpoints[i] * intervalSize;
                    } else {
                        financialCost += storageAsset.getTariffExport().orElse(0d) * -1 * setpoints[i] * intervalSize;
                    }
                }
                powerNets[i] += setpoints[i];
            }
            // Push the setpoints into the prediction service for the storage asset's setpoint attribute and set current setpoint
            List<Pair<?, LocalDateTime>> valuesAndTimestamps = IntStream.range(1, setpoints.length).mapToObj(i -> new Pair<>(setpoints[i], LocalDateTime.ofInstant(optimisationTime.plus(periodSeconds * i, ChronoUnit.SECONDS), ZoneId.systemDefault()))).collect(Collectors.toList());
            assetPredictedDatapointService.updateValues(storageAsset.getId(), ElectricityAsset.POWER_SETPOINT.getName(), valuesAndTimestamps);
        }
        assetProcessingService.sendAttributeEvent(new AttributeEvent(storageAsset.getId(), ElectricityAsset.POWER_SETPOINT, setpoints != null ? setpoints[0] : null));
        // Update unoptimised power for this asset
        obsoleteUnoptimisedAssetIds.remove(storageAsset.getId());
        double assetUnoptimisedPower = getStorageUnoptimisedImportPower(optimisationInstance, optimisationAssetId, storageAsset, maxEnergyLevelMin, Math.max(0, powerImportMax - unoptimisedPower));
        unoptimisedPower += assetUnoptimisedPower;
        unoptimisedFinancialCost += storageAsset.getTariffImport().orElse(0d) * assetUnoptimisedPower * intervalSize;
    }
    // Clear out un-optimised data for not found assets
    obsoleteUnoptimisedAssetIds.forEach(optimisationInstance.unoptimisedStorageAssetEnergyLevels.keySet()::remove);
    // Calculate and store savings data
    carbonCost = (powerNets[0] >= 0 ? supplierAsset.getCarbonImport().orElse(0d) : -1 * supplierAsset.getCarbonExport().orElse(0d)) * powerNets[0] * intervalSize;
    financialCost += (powerNets[0] >= 0 ? supplierAsset.getTariffImport().orElse(0d) : -1 * supplierAsset.getTariffExport().orElse(0d)) * powerNets[0] * intervalSize;
    unoptimisedCarbonCost = (unoptimisedPower >= 0 ? supplierAsset.getCarbonImport().orElse(0d) : -1 * supplierAsset.getCarbonExport().orElse(0d)) * unoptimisedPower * intervalSize;
    unoptimisedFinancialCost += (unoptimisedPower >= 0 ? supplierAsset.getTariffImport().orElse(0d) : -1 * supplierAsset.getTariffExport().orElse(0d)) * unoptimisedPower * intervalSize;
    double financialSaving = unoptimisedFinancialCost - financialCost;
    double carbonSaving = unoptimisedCarbonCost - carbonCost;
    LOG.info(getLogPrefix(optimisationAssetId) + "Current interval financial saving = " + financialSaving);
    LOG.info(getLogPrefix(optimisationAssetId) + "Current interval carbon saving = " + carbonSaving);
    financialSaving += optimisationInstance.optimisationAsset.getFinancialSaving().orElse(0d);
    carbonSaving += optimisationInstance.optimisationAsset.getCarbonSaving().orElse(0d);
    // Update in memory asset
    optimisationInstance.optimisationAsset.setFinancialSaving(financialSaving);
    optimisationInstance.optimisationAsset.setCarbonSaving(carbonSaving);
    // Push new values into the DB
    assetProcessingService.sendAttributeEvent(new AttributeEvent(optimisationAssetId, EnergyOptimisationAsset.FINANCIAL_SAVING, financialSaving));
    assetProcessingService.sendAttributeEvent(new AttributeEvent(optimisationAssetId, EnergyOptimisationAsset.CARBON_SAVING, carbonSaving));
}
Also used : AssetStorageService(org.openremote.manager.asset.AssetStorageService) IntStream(java.util.stream.IntStream) GatewayService.isNotForGateway(org.openremote.manager.gateway.GatewayService.isNotForGateway) java.util(java.util) DatapointInterval(org.openremote.model.datapoint.DatapointInterval) ScheduledFuture(java.util.concurrent.ScheduledFuture) AssetDescriptor(org.openremote.model.asset.AssetDescriptor) BiFunction(java.util.function.BiFunction) AttributeRef(org.openremote.model.attribute.AttributeRef) AssetProcessingService(org.openremote.manager.asset.AssetProcessingService) ValueUtil(org.openremote.model.util.ValueUtil) Function(java.util.function.Function) Level(java.util.logging.Level) java.time(java.time) BooleanPredicate(org.openremote.model.query.filter.BooleanPredicate) Attribute(org.openremote.model.attribute.Attribute) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AttributeEvent(org.openremote.model.attribute.AttributeEvent) org.openremote.model.asset.impl(org.openremote.model.asset.impl) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) PersistenceEvent(org.openremote.model.PersistenceEvent) LogicGroup(org.openremote.model.query.LogicGroup) MessageBrokerService(org.openremote.container.message.MessageBrokerService) AssetPredictedDatapointService(org.openremote.manager.datapoint.AssetPredictedDatapointService) Asset(org.openremote.model.asset.Asset) MetaItemType(org.openremote.model.value.MetaItemType) HOURS(java.time.temporal.ChronoUnit.HOURS) AssetQuery(org.openremote.model.query.AssetQuery) Pair(org.openremote.model.util.Pair) ContainerService(org.openremote.model.ContainerService) AttributePredicate(org.openremote.model.query.filter.AttributePredicate) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) Container(org.openremote.model.Container) ValueDatapoint(org.openremote.model.datapoint.ValueDatapoint) TimeUnit(java.util.concurrent.TimeUnit) ClientEventService(org.openremote.manager.event.ClientEventService) ChronoUnit(java.time.temporal.ChronoUnit) StringPredicate(org.openremote.model.query.filter.StringPredicate) RouteBuilder(org.apache.camel.builder.RouteBuilder) TimerService(org.openremote.container.timer.TimerService) PERSISTENCE_TOPIC(org.openremote.container.persistence.PersistenceService.PERSISTENCE_TOPIC) DateTimeFormatter(java.time.format.DateTimeFormatter) PersistenceService.isPersistenceEventForEntityType(org.openremote.container.persistence.PersistenceService.isPersistenceEventForEntityType) GatewayService(org.openremote.manager.gateway.GatewayService) AttributeExecuteStatus(org.openremote.model.attribute.AttributeExecuteStatus) StringPredicate(org.openremote.model.query.filter.StringPredicate) Attribute(org.openremote.model.attribute.Attribute) AttributePredicate(org.openremote.model.query.filter.AttributePredicate) AttributeEvent(org.openremote.model.attribute.AttributeEvent) BooleanPredicate(org.openremote.model.query.filter.BooleanPredicate) Pair(org.openremote.model.util.Pair) AssetQuery(org.openremote.model.query.AssetQuery) ValueDatapoint(org.openremote.model.datapoint.ValueDatapoint) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicInteger(java.util.concurrent.atomic.AtomicInteger)

Example 2 with StringPredicate

use of org.openremote.model.query.filter.StringPredicate in project openremote by openremote.

the class AgentService method startAgent.

protected void startAgent(Agent<?, ?, ?> agent) {
    withLock(getClass().getSimpleName() + "::startAgent", () -> {
        Protocol<?> protocol = null;
        try {
            protocol = agent.getProtocolInstance();
            protocolInstanceMap.put(agent.getId(), protocol);
            LOG.fine("Starting protocol instance: " + protocol);
            protocol.start(container);
            LOG.fine("Started protocol instance:" + protocol);
            LOG.finer("Linking attributes to protocol instance: " + protocol);
            // Get all assets that have attributes with agent link meta for this agent
            List<Asset<?>> assets = assetStorageService.findAll(new AssetQuery().attributes(new AttributePredicate().meta(new NameValuePredicate(AGENT_LINK, new StringPredicate(agent.getId()), false, new NameValuePredicate.Path("id")))));
            LOG.finer("Found '" + assets.size() + "' asset(s) with attributes linked to this protocol instance: " + protocol);
            assets.forEach(asset -> getGroupedAgentLinkAttributes(asset.getAttributes().stream(), assetAttribute -> assetAttribute.getMetaValue(AGENT_LINK).map(agentLink -> agentLink.getId().equals(agent.getId())).orElse(false)).forEach((agnt, attributes) -> linkAttributes(agnt, asset.getId(), attributes)));
        } catch (Exception e) {
            if (protocol != null) {
                try {
                    protocol.stop(container);
                } catch (Exception ignored) {
                }
            }
            protocolInstanceMap.remove(agent.getId());
            LOG.log(Level.SEVERE, "Failed to start protocol instance for agent: " + agent, e);
            sendAttributeEvent(new AttributeEvent(agent.getId(), Agent.STATUS.getName(), ConnectionStatus.ERROR));
        }
    });
}
Also used : Protocol(org.openremote.model.asset.agent.Protocol) AssetProcessingException(org.openremote.manager.asset.AssetProcessingException) AssetProcessingService(org.openremote.manager.asset.AssetProcessingService) ASSET_QUEUE(org.openremote.manager.asset.AssetProcessingService.ASSET_QUEUE) ProtocolInstanceDiscovery(org.openremote.model.protocol.ProtocolInstanceDiscovery) ACTUATOR_TOPIC(org.openremote.model.asset.agent.Protocol.ACTUATOR_TOPIC) AgentLink(org.openremote.model.asset.agent.AgentLink) Future(java.util.concurrent.Future) TextUtil(org.openremote.model.util.TextUtil) Attribute.getAddedOrModifiedAttributes(org.openremote.model.attribute.Attribute.getAddedOrModifiedAttributes) AssetTreeNode(org.openremote.model.asset.AssetTreeNode) Predicate(java.util.function.Predicate) ProtocolAssetDiscovery(org.openremote.model.protocol.ProtocolAssetDiscovery) ContainerService(org.openremote.model.ContainerService) AttributePredicate(org.openremote.model.query.filter.AttributePredicate) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) Container(org.openremote.model.Container) Stream(java.util.stream.Stream) StringPredicate(org.openremote.model.query.filter.StringPredicate) RouteBuilder(org.apache.camel.builder.RouteBuilder) PERSISTENCE_TOPIC(org.openremote.container.persistence.PersistenceService.PERSISTENCE_TOPIC) org.openremote.model.attribute(org.openremote.model.attribute) Agent(org.openremote.model.asset.agent.Agent) PathPredicate(org.openremote.model.query.filter.PathPredicate) GatewayService(org.openremote.manager.gateway.GatewayService) GlobalLock.withLock(org.openremote.container.concurrent.GlobalLock.withLock) AssetStorageService(org.openremote.manager.asset.AssetStorageService) GatewayService.isNotForGateway(org.openremote.manager.gateway.GatewayService.isNotForGateway) java.util(java.util) ConnectionStatus(org.openremote.model.asset.agent.ConnectionStatus) Level(java.util.logging.Level) GlobalLock.withLockReturning(org.openremote.container.concurrent.GlobalLock.withLockReturning) AGENT_LINK(org.openremote.model.value.MetaItemType.AGENT_LINK) Collectors.mapping(java.util.stream.Collectors.mapping) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) NameValuePredicate(org.openremote.model.query.filter.NameValuePredicate) ManagerWebService(org.openremote.manager.web.ManagerWebService) PersistenceEvent(org.openremote.model.PersistenceEvent) MessageBrokerService(org.openremote.container.message.MessageBrokerService) ManagerIdentityService(org.openremote.manager.security.ManagerIdentityService) Asset(org.openremote.model.asset.Asset) AssetQuery(org.openremote.model.query.AssetQuery) Pair(org.openremote.model.util.Pair) ProtocolAssetService(org.openremote.agent.protocol.ProtocolAssetService) EntityManager(javax.persistence.EntityManager) HEADER_SOURCE(org.openremote.model.attribute.AttributeEvent.HEADER_SOURCE) Consumer(java.util.function.Consumer) SENSOR_QUEUE(org.openremote.model.asset.agent.Protocol.SENSOR_QUEUE) ClientEventService(org.openremote.manager.event.ClientEventService) ProtocolAssetImport(org.openremote.model.protocol.ProtocolAssetImport) Collectors.toList(java.util.stream.Collectors.toList) TimerService(org.openremote.container.timer.TimerService) AssetUpdateProcessor(org.openremote.manager.asset.AssetUpdateProcessor) PersistenceService.isPersistenceEventForEntityType(org.openremote.container.persistence.PersistenceService.isPersistenceEventForEntityType) Source(org.openremote.model.attribute.AttributeEvent.Source) StringPredicate(org.openremote.model.query.filter.StringPredicate) AssetQuery(org.openremote.model.query.AssetQuery) Asset(org.openremote.model.asset.Asset) NameValuePredicate(org.openremote.model.query.filter.NameValuePredicate) AttributePredicate(org.openremote.model.query.filter.AttributePredicate) AssetProcessingException(org.openremote.manager.asset.AssetProcessingException)

Example 3 with StringPredicate

use of org.openremote.model.query.filter.StringPredicate in project openremote by openremote.

the class ManagerIdentityProvider method getUsersFromDb.

static User[] getUsersFromDb(PersistenceService persistenceService, UserQuery query) {
    StringBuilder sb = new StringBuilder();
    List<Object> parameters = new ArrayList<>();
    final UserQuery userQuery = query != null ? query : new UserQuery();
    // BUILD SELECT
    sb.append("SELECT u");
    // BUILD FROM
    sb.append(" FROM User u");
    if (userQuery.assetPredicate != null || userQuery.pathPredicate != null) {
        sb.append(" join UserAssetLink ua on ua.id.userId = u.id");
    }
    // BUILD WHERE
    sb.append(" WHERE 1=1");
    if (userQuery.tenantPredicate != null && !TextUtil.isNullOrEmpty(userQuery.tenantPredicate.realm)) {
        sb.append(" AND u.realm = ?").append(parameters.size() + 1);
        parameters.add(userQuery.tenantPredicate.realm);
    }
    if (userQuery.assetPredicate != null) {
        sb.append(" AND ua.id.assetId = ?").append(parameters.size() + 1);
        parameters.add(userQuery.assetPredicate.id);
    }
    if (userQuery.pathPredicate != null) {
        sb.append(" AND ?").append(parameters.size() + 1).append(" <@ get_asset_tree_path(ua.asset_id)");
        parameters.add(userQuery.pathPredicate.path);
    }
    if (userQuery.ids != null && userQuery.ids.length > 0) {
        sb.append(" AND u.id IN (?").append(parameters.size() + 1);
        parameters.add(userQuery.ids[0]);
        for (int i = 1; i < userQuery.ids.length; i++) {
            sb.append(",?").append(parameters.size() + 1);
            parameters.add(userQuery.ids[i]);
        }
        sb.append(")");
    }
    if (userQuery.usernames != null && userQuery.usernames.length > 0) {
        sb.append(" and (");
        boolean isFirst = true;
        for (StringPredicate pred : userQuery.usernames) {
            if (!isFirst) {
                sb.append(" or ");
            }
            isFirst = false;
            final int pos = parameters.size() + 1;
            // No case support for username
            sb.append("upper(u.username)");
            sb.append(buildMatchFilter(pred, pos));
            parameters.add(pred.prepareValue());
        }
        sb.append(")");
    }
    if (userQuery.select != null && userQuery.select.excludeRegularUsers) {
        sb.append(" and u.secret IS NOT NULL");
    } else if (userQuery.select != null && userQuery.select.excludeServiceUsers) {
        sb.append(" and u.secret IS NULL");
    }
    // BUILD ORDER BY
    if (userQuery.orderBy != null) {
        if (userQuery.orderBy.property != null) {
            sb.append(" ORDER BY");
            switch(userQuery.orderBy.property) {
                case CREATED_ON:
                    sb.append(" u.createdOn");
                    break;
                case FIRST_NAME:
                    sb.append(" u.firstName");
                    break;
                case LAST_NAME:
                    sb.append(" u.lastName");
                    break;
                case USERNAME:
                    // Remove service user prefix
                    sb.append(" replace(u.username, '").append(User.SERVICE_ACCOUNT_PREFIX).append("', '')");
                    break;
                case EMAIL:
                    sb.append(" u.email");
                    break;
                default:
                    throw new UnsupportedOperationException("Unsupported order by value: " + userQuery.orderBy.property);
            }
            if (userQuery.orderBy.descending) {
                sb.append(" DESC");
            }
        }
    }
    List<User> users = persistenceService.doReturningTransaction(entityManager -> {
        TypedQuery<User> sqlQuery = entityManager.createQuery(sb.toString(), User.class);
        IntStream.range(0, parameters.size()).forEach(i -> sqlQuery.setParameter(i + 1, parameters.get(i)));
        if (userQuery.limit != null && userQuery.limit > 0) {
            sqlQuery.setMaxResults(userQuery.limit);
        }
        if (userQuery.offset != null && userQuery.offset > 0) {
            sqlQuery.setFirstResult(query.offset);
        }
        return sqlQuery.getResultList();
    });
    if (userQuery.select != null && (userQuery.select.basic || userQuery.select.excludeSystemUsers)) {
        // TODO: Move this within the query
        return users.stream().filter(user -> {
            boolean keep = !userQuery.select.excludeSystemUsers || !user.isSystemAccount();
            if (keep && userQuery.select.basic) {
                // Clear out data and leave only basic info
                user.setAttributes(null);
                user.setEmail(null);
                user.setRealmId(null);
                user.setSecret(null);
            }
            return keep;
        }).toArray(User[]::new);
    }
    return users.toArray(new User[0]);
}
Also used : IdentityProvider(org.openremote.container.security.IdentityProvider) AssetStorageService(org.openremote.manager.asset.AssetStorageService) org.openremote.model.security(org.openremote.model.security) IntStream(java.util.stream.IntStream) java.util(java.util) AssetStorageService.buildMatchFilter(org.openremote.manager.asset.AssetStorageService.buildMatchFilter) AuthContext(org.openremote.container.security.AuthContext) MASTER_REALM(org.openremote.model.Constants.MASTER_REALM) TypedQuery(javax.persistence.TypedQuery) Collectors(java.util.stream.Collectors) TenantFilter(org.openremote.model.event.shared.TenantFilter) StringPredicate(org.openremote.model.query.filter.StringPredicate) UserQuery(org.openremote.model.query.UserQuery) PersistenceService(org.openremote.container.persistence.PersistenceService) TextUtil(org.openremote.model.util.TextUtil) StringPredicate(org.openremote.model.query.filter.StringPredicate) UserQuery(org.openremote.model.query.UserQuery)

Example 4 with StringPredicate

use of org.openremote.model.query.filter.StringPredicate in project openremote by openremote.

the class ManagerKeycloakIdentityProvider method queryUsers.

@Override
public User[] queryUsers(UserQuery userQuery) {
    if (userQuery == null) {
        userQuery = new UserQuery();
    }
    if (userQuery.usernames == null) {
        userQuery.usernames = new StringPredicate[1];
        userQuery.usernames(new StringPredicate(AssetQuery.Match.BEGIN, User.SERVICE_ACCOUNT_PREFIX).negate(true));
    } else {
        userQuery.usernames = Arrays.copyOf(userQuery.usernames, userQuery.usernames.length + 1);
        userQuery.usernames[userQuery.usernames.length - 1] = new StringPredicate(AssetQuery.Match.BEGIN, User.SERVICE_ACCOUNT_PREFIX).negate(true);
    }
    return ManagerIdentityProvider.getUsersFromDb(persistenceService, userQuery);
}
Also used : StringPredicate(org.openremote.model.query.filter.StringPredicate) UserQuery(org.openremote.model.query.UserQuery)

Example 5 with StringPredicate

use of org.openremote.model.query.filter.StringPredicate in project openremote by openremote.

the class ConsoleResourceImpl method getConsoleParentAsset.

public static Asset<?> getConsoleParentAsset(AssetStorageService assetStorageService, Tenant tenant) {
    // Look for a group asset with a child type of console in the realm root
    GroupAsset consoleParent = (GroupAsset) assetStorageService.find(new AssetQuery().select(new AssetQuery.Select().excludeAttributes()).names(CONSOLE_PARENT_ASSET_NAME).parents(new ParentPredicate(null)).types(GroupAsset.class).tenant(new TenantPredicate(tenant.getRealm())).attributes(new AttributePredicate("childAssetType", new StringPredicate(ConsoleAsset.DESCRIPTOR.getName()))));
    if (consoleParent == null) {
        consoleParent = new GroupAsset(CONSOLE_PARENT_ASSET_NAME, ConsoleAsset.class);
        consoleParent.setChildAssetType(ConsoleAsset.DESCRIPTOR.getName());
        consoleParent.setRealm(tenant.getRealm());
        consoleParent = assetStorageService.merge(consoleParent);
    }
    return consoleParent;
}
Also used : ConsoleAsset(org.openremote.model.asset.impl.ConsoleAsset) ParentPredicate(org.openremote.model.query.filter.ParentPredicate) StringPredicate(org.openremote.model.query.filter.StringPredicate) AssetQuery(org.openremote.model.query.AssetQuery) GroupAsset(org.openremote.model.asset.impl.GroupAsset) TenantPredicate(org.openremote.model.query.filter.TenantPredicate) AttributePredicate(org.openremote.model.query.filter.AttributePredicate)

Aggregations

StringPredicate (org.openremote.model.query.filter.StringPredicate)5 java.util (java.util)3 Collectors (java.util.stream.Collectors)3 AssetStorageService (org.openremote.manager.asset.AssetStorageService)3 AssetQuery (org.openremote.model.query.AssetQuery)3 AttributePredicate (org.openremote.model.query.filter.AttributePredicate)3 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)2 Level (java.util.logging.Level)2 Logger (java.util.logging.Logger)2 IntStream (java.util.stream.IntStream)2 RouteBuilder (org.apache.camel.builder.RouteBuilder)2 MessageBrokerService (org.openremote.container.message.MessageBrokerService)2 PERSISTENCE_TOPIC (org.openremote.container.persistence.PersistenceService.PERSISTENCE_TOPIC)2 PersistenceService.isPersistenceEventForEntityType (org.openremote.container.persistence.PersistenceService.isPersistenceEventForEntityType)2 TimerService (org.openremote.container.timer.TimerService)2 AssetProcessingService (org.openremote.manager.asset.AssetProcessingService)2 ClientEventService (org.openremote.manager.event.ClientEventService)2 GatewayService (org.openremote.manager.gateway.GatewayService)2 GatewayService.isNotForGateway (org.openremote.manager.gateway.GatewayService.isNotForGateway)2 Container (org.openremote.model.Container)2