Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,37 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.openremote.extension.ems.agent.*;
import org.openremote.container.persistence.PersistenceService;
import org.openremote.container.timer.TimerService;
import org.openremote.extension.ems.agent.*;
import org.openremote.manager.app.ConfigurationService;
import org.openremote.manager.asset.AssetProcessingService;
import org.openremote.manager.asset.AssetStorageService;
import org.openremote.manager.dashboard.DashboardStorageService;
import org.openremote.manager.event.ClientEventService;
import org.openremote.model.Constants;
import org.openremote.model.Container;
import org.openremote.model.ContainerService;
import org.openremote.model.asset.AssetFilter;
import org.openremote.model.attribute.Attribute;
import org.openremote.model.attribute.AttributeEvent;
import org.openremote.model.attribute.MetaItem;
import org.openremote.model.dashboard.Dashboard;
import org.openremote.model.manager.ManagerAppConfig;
import org.openremote.model.query.AssetQuery;
import org.openremote.model.rules.RealmRuleset;
import org.openremote.model.syslog.SyslogCategory;
import org.openremote.model.util.UniqueIdentifierGenerator;
import org.openremote.model.util.ValueUtil;
import org.openremote.model.value.MetaItemType;
import org.openremote.model.value.ValueType;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
Expand All @@ -60,18 +67,21 @@ public class EmsOptimisationSetupService implements ContainerService {
protected AssetStorageService assetStorageService;
protected ClientEventService clientEventService;
private ConfigurationService configurationService;
protected DashboardStorageService dashboardStorageService;
protected PersistenceService persistenceService;
protected ScheduledExecutorService scheduledExecutorService;

protected TimerService timerService;

@Override
public void init(Container container) throws Exception {
assetProcessingService = container.getService(AssetProcessingService.class);
assetStorageService = container.getService(AssetStorageService.class);
clientEventService = container.getService(ClientEventService.class);
configurationService = container.getService(ConfigurationService.class);
dashboardStorageService = container.getService(DashboardStorageService.class);
persistenceService = container.getService(PersistenceService.class);
scheduledExecutorService = container.getScheduledExecutor();
timerService = container.getService(TimerService.class);
}

@Override
Expand Down Expand Up @@ -120,16 +130,15 @@ private void processAttributeEventEnergyOptimisationSetupAsset(AttributeEvent at
try {
updateManagerConfig();
String infoFieldMessage = createEnergyManagementSystem(setupAsset);

// Add a 1-second delay to ensure the info field is updated after all assets and rules are merged
scheduledExecutorService.schedule(() -> assetProcessingService.sendAttributeEvent(new AttributeEvent(setupAsset.getId(), EmsEnergyOptimisationSetupAsset.INFO_FIELD, infoFieldMessage), getClass().getSimpleName()), 1, TimeUnit.SECONDS);

} catch (Exception e) {
LOG.warning(String.format("assetName='%s', assetId='%s'; An exception occurred during energy management system creation; Exception: %s", setupAsset.getName(), setupAsset.getId(), e));
}
}
}


@SuppressWarnings("unchecked")
private void updateManagerConfig() {
ManagerAppConfig managerConfig = configurationService.getManagerConfig();
Expand Down Expand Up @@ -161,7 +170,8 @@ private Map<String, Object> getEmsAssetTypesConfig() {

String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(mapper.readTree(json), new TypeReference<>() {});
return mapper.convertValue(mapper.readTree(json), new TypeReference<>() {
});
} catch (Exception e) {
throw new RuntimeException("Failed to read resource: " + path, e);
}
Expand Down Expand Up @@ -195,12 +205,14 @@ private String createEnergyManagementSystem(EmsEnergyOptimisationSetupAsset setu
return infoFieldMessage;
}


// Create Energy Optimisation Asset
EmsEnergyOptimisationAsset energyOptimisationAsset = new EmsEnergyOptimisationAsset(energyOptimisationAssetName);
energyOptimisationAsset.setId(UniqueIdentifierGenerator.generateId()).setParent(setupAsset);

double powerLimitMaximum = 500.0;
double powerLimitMinimum = -500.0;
double powerFluctuation = 40.0;
Double powerConsumption = 400.0;

String powerLimitMaximumProfileCsv = generatePowerLimitProfile(powerLimitMaximum);
Expand All @@ -219,6 +231,19 @@ private String createEnergyManagementSystem(EmsEnergyOptimisationSetupAsset setu
// .setPowerNet(powerConsumption)
;

energyOptimisationAsset.addOrReplaceAttributes(
new Attribute<>("powerLimitMaximumFluctuationMargin", ValueType.POSITIVE_NUMBER, powerFluctuation)
.addOrReplaceMeta(
new MetaItem<>(MetaItemType.READ_ONLY),
new MetaItem<>(MetaItemType.UNITS, Constants.units(Constants.UNITS_KILO, Constants.UNITS_WATT))
),
new Attribute<>("powerLimitMinimumFluctuationMargin", ValueType.POSITIVE_NUMBER, powerFluctuation)
.addOrReplaceMeta(
new MetaItem<>(MetaItemType.READ_ONLY),
new MetaItem<>(MetaItemType.UNITS, Constants.units(Constants.UNITS_KILO, Constants.UNITS_WATT))
)
);

assetStorageService.merge(energyOptimisationAsset);

// Create Electricity Battery Asset
Expand Down Expand Up @@ -260,33 +285,38 @@ private String createEnergyManagementSystem(EmsEnergyOptimisationSetupAsset setu
assetStorageService.merge(gopacsAsset);
}


// Setup rules
String realmName = setupAsset.getRealm();
String energyOptimisationAssetId = energyOptimisationAsset.getId();
String electricityBatteryAssetId = electricityBatteryAsset.getId();

try (InputStream inputStream = EmsOptimisationService.class.getResourceAsStream("/ems/rules/EmsDemoSimulationRules.groovy")) {
if (inputStream != null) {
String realmName = setupAsset.getRealm();
String rulesName = energyManagementSystemName + ": Demo simulation rules";

String rules = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

// General variables rules
rules = rules.replaceFirst("setId1", energyOptimisationAsset.getId());
rules = rules.replaceFirst("setId1", energyOptimisationAssetId);
rules = rules.replaceFirst("setValue1", String.valueOf(powerConsumption));
rules = rules.replaceFirst("setValue2", "1");
rules = rules.replaceFirst("setValue3", String.valueOf(powerFluctuation));

// Link forecasts rule
rules = rules.replaceFirst("linkInputAssetId1", electricityBatteryAsset.getId());
rules = rules.replaceFirst("linkInputAssetId1", electricityBatteryAssetId);
rules = rules.replaceFirst("linkInputAttributeName1", EmsElectricityBatteryAsset.POWER_SETPOINT.getName());
rules = rules.replaceFirst("linkOutputAssetId1", energyOptimisationAsset.getId());
rules = rules.replaceFirst("linkOutputAssetId1", energyOptimisationAssetId);
rules = rules.replaceFirst("linkOutputAttributeName1", EmsEnergyOptimisationAsset.POWER_FLEXIBLE.getName());

// Sum forecasts rule
rules = rules.replaceFirst("sumInputAssetId1", energyOptimisationAsset.getId());
rules = rules.replaceFirst("sumInputAssetId1", energyOptimisationAssetId);
rules = rules.replaceFirst("sumInputAttributeName1", EmsEnergyOptimisationAsset.POWER_CONSUMPTION.getName());
rules = rules.replaceFirst("sumInputAssetId2", energyOptimisationAsset.getId());
rules = rules.replaceFirst("sumInputAssetId2", energyOptimisationAssetId);
rules = rules.replaceFirst("sumInputAttributeName2", EmsEnergyOptimisationAsset.POWER_PRODUCTION.getName());
rules = rules.replaceFirst("sumInputAssetId3", energyOptimisationAsset.getId());
rules = rules.replaceFirst("sumInputAssetId3", energyOptimisationAssetId);
rules = rules.replaceFirst("sumInputAttributeName3", EmsEnergyOptimisationAsset.POWER_FLEXIBLE.getName());
rules = rules.replaceFirst("sumOutputAssetId", energyOptimisationAsset.getId());
rules = rules.replaceFirst("sumOutputAssetId", energyOptimisationAssetId);
rules = rules.replaceFirst("sumOutputAttributeName", EmsEnergyOptimisationAsset.POWER_NET.getName());

RealmRuleset districtRuleSet = new RealmRuleset(realmName, rulesName, GROOVY, rules);
Expand All @@ -295,9 +325,67 @@ private String createEnergyManagementSystem(EmsEnergyOptimisationSetupAsset setu
persistenceService.doReturningTransaction(entityManager -> entityManager.merge(districtRuleSet));
}
} catch (Exception e) {
LOG.warning(String.format("assetName='%s', assetId='%s'; Rule were not created for energy management system '%s'; Exception: %s", setupAsset.getName(), setupAsset.getId(), energyOptimisationAssetName, e));
LOG.warning(String.format("assetName='%s', assetId='%s'; Rules were not created for energy management system '%s'; Exception: %s", setupAsset.getName(), setupAsset.getId(), energyOptimisationAssetName, e));
}

Instant currentDate = timerService.getNow();

// Create main dashboard
try (InputStream inputStream = EmsOptimisationService.class.getResourceAsStream("/ems/dashboards/EmsOverviewDashboard.json")) {
String dashboardName = energyManagementSystemName + ": Overview";
if (inputStream != null) {

String dashboardStr = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

dashboardStr = dashboardStr
.replace("setAssetId1", energyOptimisationAssetId)
.replace("setTemplateId1", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId1", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId2", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId3", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId4", UniqueIdentifierGenerator.generateId())
;

Dashboard dashboard = ValueUtil.JSON.readValue(dashboardStr, Dashboard.class);

dashboard.setCreatedOn(currentDate);
dashboard.setRealm(realmName);
dashboard.setDisplayName(dashboardName);

dashboardStorageService.createNew(dashboard);
}
Comment thread
wborn marked this conversation as resolved.
} catch (Exception e) {
LOG.warning(String.format("assetName='%s', assetId='%s'; Dashboard was not created for energy management system '%s'; Exception: %s", setupAsset.getName(), setupAsset.getId(), energyOptimisationAssetName, e));
}

// Create battery dashboard
try (InputStream inputStream = EmsOptimisationService.class.getResourceAsStream("/ems/dashboards/EmsBatteryDashboard.json")) {
String dashboardName = energyManagementSystemName + ": Battery";
if (inputStream != null) {

String dashboardStr = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

dashboardStr = dashboardStr
.replace("setAssetId1", electricityBatteryAssetId)
.replace("setTemplateId1", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId1", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId2", UniqueIdentifierGenerator.generateId())
.replace("setWidgetId3", UniqueIdentifierGenerator.generateId())
;

Dashboard dashboard = ValueUtil.JSON.readValue(dashboardStr, Dashboard.class);

dashboard.setCreatedOn(currentDate);
dashboard.setRealm(realmName);
dashboard.setDisplayName(dashboardName);

dashboardStorageService.createNew(dashboard);
}
Comment thread
wborn marked this conversation as resolved.
} catch (Exception e) {
LOG.warning(String.format("assetName='%s', assetId='%s'; Dashboard was not created for energy management system '%s'; Exception: %s", setupAsset.getName(), setupAsset.getId(), energyOptimisationAssetName, e));
}


// Create info field message
infoFieldMessage = "Created energy management system \"" + energyOptimisationAssetName + "\":\n" +
"\n" +
Expand Down
Loading
Loading