diff --git a/README.md b/README.md index f5fc76eb..9479da59 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,15 @@ Stores solar data in a database to view on Android, Grafana, or PVOutput -

- Supported Products • - Documentation • - Features • - Supported Databases • - Examples -

+View full documentation at https://solarthing.readthedocs.io/ + +Contents + +* [Supported Products](#supported-products) +* [Features](#features) +* [Viewing Your Data](#viewing-your-data) +* [Supported Databases](#supported-databases) +* [Screenshots and Examples](#screenshots-and-examples) ## Supported Products * **Outback MATEs** (FX Inverter, MX/FM Charge Controller) @@ -41,29 +43,49 @@ Ready to install? Use the [Quickstart](https://solarthing.readthedocs.io/en/late * Can [report CPU temperature](https://solarthing.readthedocs.io/en/latest/config/file/base-json/request/cpu-temperature.html). * Runs inside a Docker container + +## Viewing Your Data + +* Grafana (recommended) + * Use SolarThing Server (with CouchDB) alongside [Wild GraphQL Data Source](https://grafana.com/grafana/plugins/retrodaredevil-wildgraphql-datasource/) + * Alternatively, configure SolarThing to upload to InfluxDB for viewing of statistics in Grafana +* [SolarThing Android](https://play.google.com/store/apps/details?id=me.retrodaredevil.solarthing.android) + * SolarThing Android connects directly to CouchDB to display data in a persistent notification +* [PVOutput.org](https://pvoutput.org) + * Upload your data to CouchDB, then let SolarThing upload the data inside your database to PVOutput! + +If you are wondering how to set up SolarThing to view your data, you can head here: https://solarthing.readthedocs.io/en/latest/quickstart/data/index.html + ## Supported Databases + * CouchDB - * Allows for [SolarThing Android](https://github.com/wildmountainfarms/solarthing-android) and [SolarThing Server](https://solarthing.readthedocs.io/en/latest/quickstart/data/solarthing-server/index.html) to function - * Used for PVOutput data collection -* GraphQL - * Allows use of CouchDB SolarThing data with Grafana - * Supplements the CouchDB database + * **Recommended** database and best supported database for SolarThing + * Used with [Wild GraphQL Data Source](https://grafana.com/grafana/plugins/retrodaredevil-wildgraphql-datasource/) to view data in Grafana + * Used with SolarThing Android to view data in the Android app + * Used as intermediate storage before data is aggregated and uploaded to PVOutput * InfluxDB - * Simplest to set up with Grafana -* [PVOutput.org](https://pvoutput.org) - * Allows for viewing of data on [pvoutput.org](https://pvoutput.org) - * Requires CouchDB to be set up + * Upload statistics to InfluxDB and view them in your visualization tool of choice (Grafana is an option) * REST API * With the "post" database, all packets can be posted to a URL endpoint, useful for REST APIs -## Examples -PVOutput Wild Mountain Farms: [PVOutput System](https://pvoutput.org/intraday.jsp?sid=72206) and +## Screenshots and Examples + +You can get data in [Grafana](https://github.com/grafana/grafana) via **CouchDB+SolarThing Server** or via InfluxDB (InfluxDB not recommended). + +Grafana is customizable. Rearrange graphs and make it how you want! +Pre-made Grafana dashboards are coming soon. + +![alt text](other/docs/grafana-screenshot-2024-04-21.png "SolarThing with Grafana") + +--- + +PVOutput Wild Mountain Farms: [PVOutput System](https://pvoutput.org/intraday.jsp?sid=72206) and [PVOutput SolarThing Teams](https://pvoutput.org/listteam.jsp?tid=1528) --- -SolarThing Android: [Github](https://github.com/wildmountainfarms/solarthing-android) +SolarThing Android: [GitHub](https://github.com/wildmountainfarms/solarthing-android) | [Google Play](https://play.google.com/store/apps/details?id=me.retrodaredevil.solarthing.android) @@ -71,35 +93,6 @@ SolarThing Android displays data in a persistent notification that updates at a ![alt text](other/docs/solarthing-android-notification-screenshot-1.jpg "SolarThing Android Notification")
-You can get data in [Grafana](https://github.com/grafana/grafana) via InfluxDB or via CouchDB+SolarThing GraphQL. - -Grafana is very customizable. Rearrange graphs and make it how you want! -![alt text](other/docs/grafana-screenshot-1.png "SolarThing with Grafana") - ---- - -### Usage at Wild Mountain Farms -We monitor an Outback MATE2, Renogy Rover PG 40A, EPEver Tracer2210AN (20A) using a Raspberry Pi 3. -Each device has its own instance of SolarThing running. Each instance uploads data to CouchDB. CouchDB, Grafana, -and SolarThing GraphQL run on a separate "NAS" computer. This NAS runs the automation and pvoutput programs. -The automation program handles the sending of Slack messages for low battery notifications. - -## Database Setup -* [CouchDB setup](https://solarthing.readthedocs.io/en/latest/quickstart/config/database/couchdb.html)
- * Used for SolarThing Android, and SolarThing Server -* [InfluxDB 2.0 setup](https://solarthing.readthedocs.io/en/latest/quickstart/config/database/influxdb2.html)
- * Used for direct Grafana queries - -## [Developer Use](other/docs/developer_use.md) -## [Contributing](CONTRIBUTING.md) -## [Updating](https://solarthing.readthedocs.io/en/latest/updating.html) - -## Configuration -This uses all JSON for configuring everything. The files you edit are all in one place unless you decide to move them. - -See [configuration](https://solarthing.readthedocs.io/en/latest/configuration.html) to see how to set them up - -## [SolarThing Alternatives](https://solarthing.readthedocs.io/en/latest/misc/alternatives.html) ## Suggestions? If you have suggestions on how to improve the documentation or have a feature request, I'd love to diff --git a/core/src/main/java/me/retrodaredevil/solarthing/packets/identification/IdentityInfo.java b/core/src/main/java/me/retrodaredevil/solarthing/packets/identification/IdentityInfo.java index 465551bd..b03ea1b7 100644 --- a/core/src/main/java/me/retrodaredevil/solarthing/packets/identification/IdentityInfo.java +++ b/core/src/main/java/me/retrodaredevil/solarthing/packets/identification/IdentityInfo.java @@ -19,7 +19,7 @@ public interface IdentityInfo { // Note the JsonProperty annotations are for GraphQL. These are not meant to be serialized and saved to a database @JsonProperty("displayName") - default String getDisplayName() { // FX 1, MX 2, Rover 40A + default @NotNull String getDisplayName() { // FX 1, MX 2, Rover 40A String suffix = getSuffix(); if (suffix.isEmpty()) { return getName(); diff --git a/other/docs/grafana-screenshot-2024-04-21.png b/other/docs/grafana-screenshot-2024-04-21.png new file mode 100644 index 00000000..05af856c Binary files /dev/null and b/other/docs/grafana-screenshot-2024-04-21.png differ diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/PacketFinder.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/PacketFinder.java index 73ee63d6..b39f0445 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/PacketFinder.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/PacketFinder.java @@ -33,7 +33,7 @@ public PacketFinder(SimpleQueryHandler simpleQueryHandler) { } } private void updateWithRange(long queryStart, long queryEnd) { - List rawPackets = simpleQueryHandler.queryStatus(queryStart, queryEnd, null); + List rawPackets = simpleQueryHandler.queryStatus(queryStart, queryEnd, null, null); synchronized (cacheMap) { for (InstancePacketGroup instancePacketGroup : rawPackets) { int fragmentId = instancePacketGroup.getFragmentId(); diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/SimpleQueryHandler.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/SimpleQueryHandler.java index e50f1c68..df7a72ae 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/SimpleQueryHandler.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/SimpleQueryHandler.java @@ -5,6 +5,7 @@ import me.retrodaredevil.couchdbjava.CouchDbInstance; import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.annotations.NotNull; +import me.retrodaredevil.solarthing.annotations.Nullable; import me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings; import me.retrodaredevil.solarthing.database.MillisDatabase; import me.retrodaredevil.solarthing.database.MillisQuery; @@ -15,13 +16,17 @@ import me.retrodaredevil.solarthing.database.couchdb.CouchDbSolarThingDatabase; import me.retrodaredevil.solarthing.database.exception.NotFoundSolarThingDatabaseException; import me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException; +import me.retrodaredevil.solarthing.packets.collection.DefaultInstanceOptions; +import me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup; +import me.retrodaredevil.solarthing.packets.collection.InstancePacketGroup; +import me.retrodaredevil.solarthing.packets.collection.PacketGroup; +import me.retrodaredevil.solarthing.packets.collection.PacketGroups; +import me.retrodaredevil.solarthing.packets.collection.parsing.PacketParsingErrorHandler; +import me.retrodaredevil.solarthing.rest.exceptions.DatabaseException; import me.retrodaredevil.solarthing.type.alter.StoredAlterPacket; import me.retrodaredevil.solarthing.type.closed.meta.DefaultMetaDatabase; import me.retrodaredevil.solarthing.type.closed.meta.EmptyMetaDatabase; import me.retrodaredevil.solarthing.type.closed.meta.MetaDatabase; -import me.retrodaredevil.solarthing.packets.collection.*; -import me.retrodaredevil.solarthing.packets.collection.parsing.PacketParsingErrorHandler; -import me.retrodaredevil.solarthing.rest.exceptions.DatabaseException; import me.retrodaredevil.solarthing.type.closed.meta.RootMetaPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +36,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -89,7 +93,7 @@ public List sortPackets(List queryPackets(MillisDatabase database, long from, long to, String sourceId) { + private List queryPackets(MillisDatabase database, long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) { MillisQuery millisQuery = new MillisQueryBuilder() .startKey(from) @@ -148,21 +152,21 @@ private List queryPackets(MillisDatabase database } return Collections.emptyList(); } - if (sourceId == null) { - return PacketGroups.parseToInstancePacketGroups(rawPacketGroups, defaultInstanceOptions); - } - Map> map = PacketGroups.parsePackets(rawPacketGroups, defaultInstanceOptions); - if(map.containsKey(sourceId)){ - List instancePacketGroupList = map.get(sourceId); - return PacketGroups.orderByFragment(instancePacketGroupList); - } - throw new NoSuchElementException("No element with sourceId: '" + sourceId + "' available keys are: " + map.keySet()); + // Note: Before 2024-04-05 this method would throw a NoSuchElementException if no packets were found under a given Source ID + // Additionally PacketGroups.orderByFragment() was used to order the result ONLY IF a Source ID was provided. + // This behavior of this method has changed since then, which may have unintended effects. + // I really don't know if the ordering by Fragment ID was necessary, and I also don't think we really need that exception to be thrown. + return rawPacketGroups.stream() + .map(packetGroup -> PacketGroups.parseToInstancePacketGroup(packetGroup, defaultInstanceOptions)) + .filter(instancePacketGroup -> sourceId == null || instancePacketGroup.getSourceId().equals(sourceId)) + .filter(instancePacketGroup -> fragmentId == null || instancePacketGroup.getFragmentId() == fragmentId) + .toList(); } - public List queryStatus(long from, long to, String sourceId) { - return queryPackets(database.getStatusDatabase(), from, to, sourceId); + public List queryStatus(long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) { + return queryPackets(database.getStatusDatabase(), from, to, sourceId, fragmentId); } - public List queryEvent(long from, long to, String sourceId) { - return queryPackets(database.getEventDatabase(), from, to, sourceId); + public List queryEvent(long from, long to, @Nullable String sourceId, @Nullable Integer fragmentId) { + return queryPackets(database.getEventDatabase(), from, to, sourceId, fragmentId); } public MetaDatabase queryMeta() { diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/packets/FragmentFilter.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/packets/FragmentFilter.java index bc48a350..3aa31f1b 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/packets/FragmentFilter.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/packets/FragmentFilter.java @@ -2,6 +2,10 @@ import me.retrodaredevil.solarthing.rest.graphql.packets.nodes.PacketNode; +/** + * @deprecated Should not be needed anymore as {@link me.retrodaredevil.solarthing.rest.graphql.SimpleQueryHandler} accepts fragmentIds for most of its methods now. + */ +@Deprecated public class FragmentFilter implements PacketFilter { private final int fragmentId; diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SchemaConstants.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SchemaConstants.java index 5f3f093f..a1cec6b1 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SchemaConstants.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SchemaConstants.java @@ -11,6 +11,7 @@ public final class SchemaConstants { public static final String DESCRIPTION_TO = "The maximum time in milliseconds since the epoch to get data from."; public static final String DESCRIPTION_OPTIONAL_SOURCE = "The Source ID to include packets from, or null to include packets from multiple sources."; public static final String DESCRIPTION_REQUIRED_SOURCE = "The Source ID to include packets from."; - public static final String DESCRIPTION_FRAGMENT_ID = "The fragment ID to include data from."; + public static final String DESCRIPTION_OPTIONAL_FRAGMENT_ID = "The fragment ID to include data from."; + public static final String DESCRIPTION_REQUIRED_FRAGMENT_ID = "The fragment ID to include data from."; } diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLDailyService.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLDailyService.java index c3a5c485..81118597 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLDailyService.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLDailyService.java @@ -280,6 +280,7 @@ public SolarThingFullDayStatusQuery queryFullDay( @GraphQLArgument(name = "from", description = "The epoch millis value that will be used to determine the starting day. Set to null to guarantee a query of a single day.") @Nullable Long from, @GraphQLArgument(name = "to", description = "The epoch millis value that will be used to determine the ending day.") long to, @GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId, @GraphQLArgument(name = "useCache", defaultValue = "false") boolean useCache){ LocalDate fromDate = Instant.ofEpochMilli(from == null ? to : from).atZone(zoneId).toLocalDate(); @@ -292,7 +293,8 @@ public SolarThingFullDayStatusQuery queryFullDay( List packets = simpleQueryHandler.queryStatus( queryStart, queryEnd, - sourceId + sourceId, + fragmentId ); return new SimpleSolarThingFullDayStatusQuery(new BasicPacketGetter(packets, PacketFilter.KEEP_ALL), simpleQueryHandler.sortPackets(packets, sourceId)); } diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLFXService.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLFXService.java index 10081d06..29b8be01 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLFXService.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLFXService.java @@ -53,7 +53,8 @@ public List> queryFXCharging( } long startTime = from - 3 * 60 * 60 * 1000; // 3 hours back - List packets = simpleQueryHandler.queryStatus(startTime, to, null); + // Don't filter on fragmentId here. Even though we are provided with one, we still want data from other fragments as those might have temperature sensor data + List packets = simpleQueryHandler.queryStatus(startTime, to, null, null); // We make masterIdIgnoreDistance null because we will only be using fragmentId as the master fragment ID Map> map = PacketGroups.sortPackets( // separate based on source ID diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLService.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLService.java index 62549c05..2cec037a 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLService.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/service/SolarThingGraphQLService.java @@ -73,16 +73,34 @@ public SolarThingGraphQLService(SimpleQueryHandler simpleQueryHandler) { @GraphQLQuery(description = "Query status packets in the specified time range.") public @NotNull SolarThingStatusQuery queryStatus( @GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, - @GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId){ - List packets = simpleQueryHandler.queryStatus(from, to, sourceId); + @GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId + ){ + List packets = simpleQueryHandler.queryStatus(from, to, sourceId, fragmentId); return new SolarThingStatusQuery(new BasicPacketGetter(packets, PacketFilter.KEEP_ALL), simpleQueryHandler.sortPackets(packets, sourceId), simpleQueryHandler); } + @GraphQLQuery(description = "Queries status packets in the specified time range while only including the specified identifier in the specified fragment") + public @NotNull SolarThingStatusQuery queryStatusIdentifier( + @GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId, + @GraphQLArgument(name = "identifier") @NotNull String identifierRepresentation, + @GraphQLArgument(name = "acceptSupplementary", defaultValue = "true") boolean acceptSupplementary + ) { + // null source ID because each fragment ID is unique, even over multiple sources + List packets = simpleQueryHandler.queryStatus(from, to, null, fragmentId); + return new SolarThingStatusQuery( + new BasicPacketGetter(packets, new IdentifierFilter(identifierRepresentation, acceptSupplementary)), + simpleQueryHandler.sortPackets(packets, null), + simpleQueryHandler + ); + } @GraphQLQuery(description = "Query the latest collection of status packets on or before the 'to' timestamp.") public @NotNull SolarThingStatusQuery queryStatusLast( @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, @GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId, @GraphQLArgument(name = "reversed", defaultValue = "false", description = "If set to true, the returned list will be reversed. Useful to set to true if you want the very latest packet to be first.") boolean reversed){ - List packets = simpleQueryHandler.queryStatus(to - SolarThingConstants.LATEST_PACKETS_DURATION.toMillis(), to, sourceId); + List packets = simpleQueryHandler.queryStatus(to - SolarThingConstants.LATEST_PACKETS_DURATION.toMillis(), to, sourceId, fragmentId); List lastPackets = new ArrayList<>(); for(List packetGroups : PacketGroups.mapFragments(packets).values()) { lastPackets.add(packetGroups.get(packetGroups.size() - 1)); @@ -98,31 +116,33 @@ public SolarThingGraphQLService(SimpleQueryHandler simpleQueryHandler) { public @NotNull SolarThingEventQuery queryEvent( @GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, @GraphQLArgument(name = "sourceId", description = DESCRIPTION_OPTIONAL_SOURCE) @Nullable String sourceId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_OPTIONAL_FRAGMENT_ID) @Nullable Integer fragmentId, @GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets ) { - return new SolarThingEventQuery(new BasicPacketGetter(simpleQueryHandler.queryEvent(from, to, sourceId), new UnknownChangePacketsFilter(includeUnknownChangePackets))); + return new SolarThingEventQuery(new BasicPacketGetter(simpleQueryHandler.queryEvent(from, to, sourceId, fragmentId), new UnknownChangePacketsFilter(includeUnknownChangePackets))); } @GraphQLQuery(description = "Queries events in the specified time range while only including the specified identifier in the specified fragment") public @NotNull SolarThingEventQuery queryEventIdentifier( @GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, - @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_FRAGMENT_ID) int fragmentId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId, @GraphQLArgument(name = "identifier") @NotNull String identifierRepresentation, @GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets, @GraphQLArgument(name = "acceptSupplementary", defaultValue = "true") boolean acceptSupplementary ) { return new SolarThingEventQuery(new BasicPacketGetter( - simpleQueryHandler.queryEvent(from, to, null), // null source ID because each fragment ID is unique, even over multiple sources - new PacketFilterMultiplexer(Arrays.asList(new FragmentFilter(fragmentId), new IdentifierFilter(identifierRepresentation, acceptSupplementary), new UnknownChangePacketsFilter(includeUnknownChangePackets))) + simpleQueryHandler.queryEvent(from, to, null, fragmentId), // null source ID because each fragment ID is unique, even over multiple sources + new PacketFilterMultiplexer(Arrays.asList(new IdentifierFilter(identifierRepresentation, acceptSupplementary), new UnknownChangePacketsFilter(includeUnknownChangePackets))) )); } - @GraphQLQuery(description = "Queries events in the specified time range while only including the specified fragment") + @Deprecated(forRemoval = true) + @GraphQLQuery(description = "Queries events in the specified time range while only including the specified fragment. Deprecated: Use queryEvent instead") public @NotNull SolarThingEventQuery queryEventFragment( @GraphQLArgument(name = "from", description = DESCRIPTION_FROM) long from, @GraphQLArgument(name = "to", description = DESCRIPTION_TO) long to, - @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_FRAGMENT_ID) int fragmentId, + @GraphQLArgument(name = "fragmentId", description = DESCRIPTION_REQUIRED_FRAGMENT_ID) int fragmentId, @GraphQLArgument(name = "includeUnknownChangePackets", defaultValue = "false", description = DESCRIPTION_INCLUDE_UNKNOWN_CHANGE) boolean includeUnknownChangePackets ) { return new SolarThingEventQuery(new BasicPacketGetter( - simpleQueryHandler.queryEvent(from, to, null), + simpleQueryHandler.queryEvent(from, to, null, null), // pass null as a fragmentId here because this is deprecated and might as well not change anything until this is removed new PacketFilterMultiplexer(Arrays.asList(new FragmentFilter(fragmentId), new UnknownChangePacketsFilter(includeUnknownChangePackets))) )); }