use of me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup in project solarthing by wildmountainfarms.
the class DeserializeTest method testRunAlertGeneratorOffWhileAuxOn.
@Test
void testRunAlertGeneratorOffWhileAuxOn() throws IOException, ParsePacketAsciiDecimalDigitException, CheckSumException {
File file = new File(ACTION_CONFIG_DIRECTORY, "alert_generator_off_while_aux_on.json");
ActionNode actionNode = MAPPER.readValue(file, ActionNode.class);
// We need to simulate an automation program environment to run this action
Duration[] timeReference = new Duration[] { Duration.ZERO };
FragmentedPacketGroup[] packetGroupReference = new FragmentedPacketGroup[] { null };
FragmentedPacketGroupProvider fragmentedPacketGroupProvider = () -> requireNonNull(packetGroupReference[0]);
InjectEnvironment injectEnvironment = new InjectEnvironment.Builder().add(new NanoTimeProviderEnvironment(() -> timeReference[0].toNanos())).add(new LatestPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(new LatestFragmentedPacketGroupEnvironment(fragmentedPacketGroupProvider)).build();
FXStatusPacket auxOnNoAC = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,00,252,136,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOffNoAC = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,00,252,008,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOnACUse = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,02,252,136,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
FXStatusPacket auxOffACUse = FXStatusPackets.createFromChars("\n1,00,00,02,123,123,00,10,000,02,252,008,000,999\r".toCharArray(), IgnoreCheckSum.IGNORE);
for (FXStatusPacket packet : new FXStatusPacket[] { auxOffNoAC, auxOnACUse, auxOffACUse }) {
// for these three cases, the action should end immediately
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(packet), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertTrue(action.isDone());
}
{
// Test that no alert is sent unless the aux is on, and it's in No AC for 30 seconds
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnNoAC), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(29));
action.update();
assertFalse(action.isDone());
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnACUse), 0L, "my_source_id", 999);
action.update();
// No alert has been sent, since it started to AC Use before the 30 second period completed.
assertTrue(action.isDone());
}
{
// Test that the alert gets sent and the action doesn't end until the 300-second timeout completes
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnNoAC), 0L, "my_source_id", 999);
Action action = actionNode.createAction(new ActionEnvironment(new VariableEnvironment(), new VariableEnvironment(), injectEnvironment));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(30));
action.update();
assertFalse(action.isDone());
packetGroupReference[0] = PacketGroups.createInstancePacketGroup(Collections.singleton(auxOnACUse), 0L, "my_source_id", 999);
action.update();
// Alert has been sent, so the action isn't going to end
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(299));
action.update();
assertFalse(action.isDone());
timeReference[0] = timeReference[0].plus(Duration.ofSeconds(1));
action.update();
// the 300-second timeout has completed, so the action will end
assertTrue(action.isDone());
}
}
use of me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup in project solarthing by wildmountainfarms.
the class PVOutputUploadMain method startRangeUpload.
private static int startRangeUpload(SimpleDate fromDate, SimpleDate toDate, PVOutputUploadProgramOptions options, SolarThingDatabase database, PVOutputHandler handler, PVOutputService service, ZoneId zoneId) {
List<AddOutputParameters> addOutputParameters = new ArrayList<>();
SimpleDate date = fromDate;
while (date.compareTo(toDate) <= 0) {
System.out.println("Doing " + date);
SimpleDate tomorrow = date.tomorrow();
long dayStart = date.getDayStartDateMillis(zoneId);
long dayEnd = tomorrow.getDayStartDateMillis(zoneId);
List<? extends PacketGroup> rawPacketGroups = null;
try {
rawPacketGroups = database.getStatusDatabase().query(new MillisQueryBuilder().startKey(dayStart).endKey(dayEnd).inclusiveEnd(false).build());
System.out.println("Got " + rawPacketGroups.size() + " packets for date: " + date.toPVOutputString());
} catch (SolarThingDatabaseException e) {
e.printStackTrace();
System.err.println("Couldn't query packets. Skipping " + date.toPVOutputString());
}
if (rawPacketGroups != null) {
List<FragmentedPacketGroup> packetGroups = PacketUtil.getPacketGroups(options.getSourceId(), options.getDefaultInstanceOptions(), rawPacketGroups);
if (packetGroups != null) {
if (!handler.checkPackets(dayStart, packetGroups)) {
System.err.println("Unsuccessfully checked packets for " + date.toPVOutputString());
try {
System.out.println(MAPPER.writeValueAsString(packetGroups.get(packetGroups.size() - 1)));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
} else {
AddStatusParameters statusParameters = handler.getStatus(dayStart, packetGroups);
AddOutputParametersBuilder outputParametersBuilder = new AddOutputParametersBuilder(statusParameters.getDate()).setGenerated(statusParameters.getEnergyGeneration()).setConsumption(statusParameters.getEnergyConsumption());
PVOutputHandler.setImportedExported(outputParametersBuilder, packetGroups, AccumulationConfig.createDefault(dayStart), options.isIncludeImport(), options.isIncludeExport());
AddOutputParameters outputParameters = outputParametersBuilder.build();
addOutputParameters.add(outputParameters);
System.out.println("Added parameters for " + date.toPVOutputString() + " to queue.");
System.out.println("Generated: " + statusParameters.getEnergyGeneration());
System.out.println(Arrays.toString(outputParameters.toCsvArray()));
System.out.println(CsvUtil.toCsvString(outputParameters.toCsvArray()));
}
} else {
System.err.println("Didn't find any packets with source: " + options.getSourceId() + " for date: " + date.toPVOutputString());
}
}
date = tomorrow;
}
System.out.println("Going to upload in batches of 30...");
for (int i = 0; i < addOutputParameters.size(); i += 30) {
if (i != 0) {
System.out.println("Sleeping...");
try {
// noinspection BusyWait
Thread.sleep(7000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Interrupted");
return SolarThingConstants.EXIT_CODE_INTERRUPTED;
}
}
int endIndex = Math.min(i + 30, addOutputParameters.size());
List<AddOutputParameters> parameters = addOutputParameters.subList(i, endIndex);
System.out.println("Going to upload from " + parameters.get(0).getOutputDate().toPVOutputString() + " to " + parameters.get(parameters.size() - 1).getOutputDate().toPVOutputString());
AddBatchOutputParameters batchOutputParameters = new ImmutableAddBatchOutputParameters(parameters);
try {
LOGGER.debug("Batch Output parameters as JSON: " + MAPPER.writeValueAsString(batchOutputParameters));
} catch (JsonProcessingException e) {
LOGGER.error("Got error serializing JSON. This should never happen.", e);
}
boolean successful = false;
for (int j = 0; j < 5; j++) {
if (j != 0) {
System.out.println("Sleeping before trying again");
try {
// noinspection BusyWait
Thread.sleep(j * 7000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Interrupted");
return SolarThingConstants.EXIT_CODE_INTERRUPTED;
}
}
Call<String> call = service.addBatchOutput(batchOutputParameters);
final Response<String> response;
try {
response = call.execute();
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error while executing");
continue;
}
if (response.isSuccessful()) {
System.out.println("Executed successfully. Result: " + response.body());
successful = true;
break;
} else {
System.err.println("Unsuccessful. Message: " + response.message() + " code: " + response.code());
}
}
if (!successful) {
System.err.println("All tries were unsuccessful. Ending");
return SolarThingConstants.EXIT_CODE_FAIL;
}
}
System.out.println("Done!");
return 0;
}
use of me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup in project solarthing by wildmountainfarms.
the class PVOutputUploadMain method startRealTimeProgram.
private static int startRealTimeProgram(PVOutputUploadProgramOptions options, SolarThingDatabase database, PVOutputHandler handler, PVOutputService service, ZoneId zoneId) {
if (options.isJoinTeams()) {
LOGGER.info("Going to join SolarThing team...");
Call<String> call = service.joinTeam(PVOutputConstants.SOLARTHING_TEAM_ID);
LOGGER.debug("Executing call");
Response<String> response = null;
try {
response = call.execute();
} catch (IOException e) {
LOGGER.error("Exception while executing", e);
}
if (response != null) {
int code = response.code();
String errorBody;
try {
ResponseBody responseBody = response.errorBody();
if (responseBody != null) {
errorBody = responseBody.string();
} else {
errorBody = "null";
}
} catch (IOException e) {
e.printStackTrace();
errorBody = "exception occurred";
}
if (code == 200) {
LOGGER.info("Joined the SolarThing team! Response: " + response.body());
} else if (code == 400) {
if (errorBody.contains("already")) {
LOGGER.info("Already joined SolarThing team. Response: " + errorBody);
} else if (errorBody.contains("must have at least")) {
LOGGER.info("We will try joining SolarThing team later once we have more outputs. Response: " + errorBody);
} else {
LOGGER.error("Error joining SolarThing team! Response: " + errorBody);
}
} else {
LOGGER.error("Unknown error joining SolarThing team! Response: " + errorBody);
}
}
}
while (!Thread.currentThread().isInterrupted()) {
LOGGER.debug("Going to do stuff now.");
long now = System.currentTimeMillis();
SimpleDate today = SimpleDate.fromDateMillis(now, zoneId);
long dayStartTimeMillis = today.getDayStartDateMillis(zoneId);
List<? extends PacketGroup> rawPacketGroups = null;
try {
rawPacketGroups = database.getStatusDatabase().query(new MillisQueryBuilder().startKey(dayStartTimeMillis).endKey(now).build());
LOGGER.debug("Got packets");
} catch (SolarThingDatabaseException e) {
LOGGER.error("Couldn't get status packets", e);
}
if (rawPacketGroups != null) {
List<FragmentedPacketGroup> packetGroups = PacketUtil.getPacketGroups(options.getSourceId(), options.getDefaultInstanceOptions(), rawPacketGroups);
if (packetGroups != null) {
FragmentedPacketGroup latestPacketGroup = packetGroups.get(packetGroups.size() - 1);
if (latestPacketGroup.getDateMillis() < now - 5 * 60 * 1000) {
LOGGER.warn("The last packet is more than 5 minutes in the past! now=" + now + " packet date=" + latestPacketGroup.getDateMillis());
try {
LOGGER.debug("Packets: " + MAPPER.writeValueAsString(latestPacketGroup.getPackets()));
} catch (JsonProcessingException e) {
LOGGER.warn("Couldn't serialize for some reason", e);
}
} else if (!handler.checkPackets(dayStartTimeMillis, packetGroups)) {
LOGGER.warn("Checking packets unsuccessful.");
} else {
AddStatusParameters parameters = handler.getStatus(dayStartTimeMillis, packetGroups);
if (uploadStatus(service, parameters) && (options.isIncludeImport() || options.isIncludeExport())) {
// only upload output if status is successful
AddOutputParametersBuilder outputParametersBuilder = new AddOutputParametersBuilder(parameters.getDate());
PVOutputHandler.setImportedExported(outputParametersBuilder, packetGroups, AccumulationConfig.createDefault(dayStartTimeMillis), options.isIncludeImport(), options.isIncludeExport());
AddOutputParameters outputParameters = outputParametersBuilder.build();
uploadOutput(service, outputParameters);
}
}
} else {
LOGGER.warn("Got " + rawPacketGroups.size() + " packets but, there must not have been any packets with the source: " + options.getSourceId());
}
}
LOGGER.debug("Going to sleep now");
try {
// noinspection BusyWait
Thread.sleep(5 * 60 * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
return SolarThingConstants.EXIT_CODE_INTERRUPTED;
}
use of me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup in project solarthing by wildmountainfarms.
the class StatusChatBotHandler method handleMessage.
@Override
public boolean handleMessage(Message message, MessageSender messageSender) {
if (ChatBotUtil.isSimilar("battery voltage", message.getText())) {
FragmentedPacketGroup packetGroup = packetGroupProvider.getPacketGroup();
Float batteryVoltageAverage = BatteryUtil.getBatteryVoltageAverage(packetGroup);
if (batteryVoltageAverage == null) {
messageSender.sendMessage("Battery voltage unavailable from latest data. Sorry!");
} else {
messageSender.sendMessage("Battery voltage: " + Formatting.HUNDREDTHS_FORMAT.format(batteryVoltageAverage));
}
return true;
} else if (ChatBotUtil.isSimilar("battery temperature", message.getText()) || ChatBotUtil.isSimilar("battery temp", message.getText())) {
FragmentedPacketGroup packetGroup = packetGroupProvider.getPacketGroup();
List<String> lines = new ArrayList<>();
for (Packet packet : packetGroup.getPackets()) {
int fragmentId = packetGroup.getFragmentId(packet);
if (packet instanceof BatteryTemperature && packet instanceof Identifiable) {
float temperature = ((BatteryTemperature) packet).getBatteryTemperatureFahrenheit();
IdentityInfo identityInfo = ((Identifiable) packet).getIdentityInfo();
lines.add(identityInfo.getDisplayName() + " (" + fragmentId + "): " + temperature + "F");
}
}
if (lines.isEmpty()) {
messageSender.sendMessage("No devices to read temperature!");
} else {
messageSender.sendMessage(String.join("\n", lines));
}
return true;
} else if (ChatBotUtil.isSimilar("alter", message.getText())) {
List<VersionedPacket<StoredAlterPacket>> alterPackets = alterPacketsProvider.getPackets();
if (alterPackets == null) {
messageSender.sendMessage("Error - Must have failed to query alter database");
} else {
List<String> scheduledCommandLines = new ArrayList<>();
for (VersionedPacket<StoredAlterPacket> versionedPacket : alterPackets) {
StoredAlterPacket storedAlterPacket = versionedPacket.getPacket();
AlterPacket alterPacket = storedAlterPacket.getPacket();
if (alterPacket instanceof ScheduledCommandPacket) {
ScheduledCommandData data = ((ScheduledCommandPacket) alterPacket).getData();
// ExecutionReason executionReason = ((ScheduledCommandPacket) alterPacket).getExecutionReason();
String timeString = TimeUtil.instantToSlackDateSeconds(Instant.ofEpochMilli(data.getScheduledTimeMillis()));
scheduledCommandLines.add(data.getCommandName() + " - " + timeString);
}
}
if (scheduledCommandLines.isEmpty()) {
messageSender.sendMessage("No scheduled commands (from " + alterPackets.size() + " alter packets)");
} else {
messageSender.sendMessage("Scheduled commands:\n\t" + String.join("\n\t", scheduledCommandLines));
}
}
return true;
}
return false;
}
Aggregations