diff --git a/solarnet/cloud-integrations/src/main/java/net/solarnetwork/central/c2c/biz/impl/AlsoEnergyCloudDatumStreamService.java b/solarnet/cloud-integrations/src/main/java/net/solarnetwork/central/c2c/biz/impl/AlsoEnergyCloudDatumStreamService.java
index 6213ba242..59a9053d9 100644
--- a/solarnet/cloud-integrations/src/main/java/net/solarnetwork/central/c2c/biz/impl/AlsoEnergyCloudDatumStreamService.java
+++ b/solarnet/cloud-integrations/src/main/java/net/solarnetwork/central/c2c/biz/impl/AlsoEnergyCloudDatumStreamService.java
@@ -23,12 +23,15 @@
package net.solarnetwork.central.c2c.biz.impl;
import static net.solarnetwork.central.c2c.biz.impl.BaseCloudIntegrationService.resolveBaseUrl;
+import static net.solarnetwork.central.c2c.domain.CloudDataValue.DEVICE_SERIAL_NUMBER_METADATA;
+import static net.solarnetwork.central.c2c.domain.CloudDataValue.dataValue;
import static net.solarnetwork.central.c2c.domain.CloudDataValue.intermediateDataValue;
import static net.solarnetwork.central.security.AuthorizationException.requireNonNullObject;
import static net.solarnetwork.util.ObjectUtils.requireNonNullArgument;
import static org.springframework.web.util.UriComponentsBuilder.fromUri;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -72,6 +75,15 @@ public class AlsoEnergyCloudDatumStreamService extends BaseOAuth2ClientCloudDatu
/** The data value filter key for a site ID. */
public static final String SITE_ID_FILTER = "siteId";
+ /**
+ * The URI path to list the hardware for a given site.
+ *
+ *
+ * Accepts a single {@code {siteId}} parameter.
+ *
+ */
+ public static final String SITE_HARDWARE_URL_TEMPLATE = "/sites/{siteId}/hardware";
+
/** The service settings. */
public static final List SETTINGS;
static {
@@ -156,6 +168,8 @@ public Iterable dataValues(UserLongCompositePK integrationId,
List result = Collections.emptyList();
if ( false ) {
// TODO
+ } else if ( filters != null && filters.get(SITE_ID_FILTER) != null ) {
+ result = siteHardware(integration, filters);
} else {
// list available sites
result = sites(integration);
@@ -185,6 +199,15 @@ private List sites(CloudIntegrationConfiguration integration) {
res -> parseSites(res.getBody()));
}
+ private List siteHardware(CloudIntegrationConfiguration integration,
+ Map filters) {
+ return restOpsHelper.httpGet("List sites", integration, JsonNode.class,
+ (req) -> fromUri(resolveBaseUrl(integration, AlsoEnergyCloudIntegrationService.BASE_URI))
+ .path(SITE_HARDWARE_URL_TEMPLATE).queryParam("includeArchivedFields", true)
+ .buildAndExpand(filters).toUri(),
+ res -> parseSiteHardware(res.getBody(), filters));
+ }
+
private static List parseSites(JsonNode json) {
assert json != null;
/*- EXAMPLE JSON:
@@ -208,4 +231,92 @@ private static List parseSites(JsonNode json) {
return result;
}
+ private static List parseSiteHardware(JsonNode json, Map filters) {
+ assert json != null;
+ /*- EXAMPLE JSON:
+ {
+ "hardware": [
+ {
+ "id": 12345,
+ "stringId": "C12345_S12345_PM0",
+ "functionCode": "PM",
+ "flags": [
+ "IsEnabled"
+ ],
+ "fieldsArchived": [
+ "KWHnet",
+ "KW",
+ "KVAR",
+ "PowerFactor",
+ "KWHrec",
+ "KWHdel",
+ "Frequency",
+ "VacA",
+ "VacB",
+ "VacC",
+ "VacAB",
+ "VacBC",
+ "VacCA",
+ "IacA",
+ "IacB",
+ "IacC"
+ ],
+ "name": "Elkor Production Meter - A",
+ "lastUpdate": "2024-11-21T17:19:02.4069164-05:00",
+ "lastUpload": "2024-11-21T17:17:00-05:00",
+ "iconUrl": "https://alsoenergy.com/Pub/Images/device/7855.png",
+ "config": {
+ "deviceType": "ProductionPowerMeter",
+ "hardwareStrId": "C12345_S12345_PM0",
+ "hardwareId": 12345,
+ "address": 1,
+ "portNumber": 1,
+ "baudRate": 9600,
+ "comType": "Rs485_2Wire",
+ "serialNumber": "12345",
+ "name": "Elkor Production Meter - A",
+ "outputHardwareId": 0,
+ "weatherStationId": 0,
+ "meterConfig": {
+ "scaleFactor": 0.0,
+ "isReversed": false,
+ "grossEnergy": "None",
+ "maxPowerKw": 58444.96,
+ "maxVoltage": 480.0,
+ "maxAmperage": 12200.0,
+ "acPhase": "Wye"
+ }
+ }
+ },
+ */
+ final String siteId = filters.get(SITE_ID_FILTER).toString();
+ final var result = new ArrayList(4);
+ for ( JsonNode meterNode : json.path("hardware") ) {
+ final JsonNode fieldsNode = meterNode.path("fieldsArchived");
+ if ( !(fieldsNode.isArray() && fieldsNode.size() > 0) ) {
+ continue;
+ }
+ final String id = meterNode.path("id").asText().trim();
+ if ( id.isEmpty() ) {
+ continue;
+ }
+ final String name = meterNode.path("name").asText().trim();
+ final var meta = new LinkedHashMap(4);
+ populateNonEmptyValue(meterNode, "functionCode", "functionCode", meta);
+ for ( JsonNode configNode : meterNode.path("config") ) {
+ populateNonEmptyValue(configNode, "serialNumber", DEVICE_SERIAL_NUMBER_METADATA, meta);
+ populateNonEmptyValue(configNode, "deviceType", "deviceType", meta);
+ }
+
+ List fields = new ArrayList<>(fieldsNode.size());
+ for ( JsonNode fieldNode : fieldsNode ) {
+ final String fieldName = fieldNode.asText();
+ fields.add(dataValue(List.of(siteId, id, fieldName), fieldName));
+ }
+
+ result.add(intermediateDataValue(List.of(siteId, id), name, meta, fields));
+ }
+ return result;
+ }
+
}