Skip to content

Commit

Permalink
Merge pull request #75 from wildmountainfarms/local-actions
Browse files Browse the repository at this point in the history
Local actions
  • Loading branch information
retrodaredevil authored Nov 8, 2022
2 parents 0d49a74 + 889c518 commit d45605c
Show file tree
Hide file tree
Showing 51 changed files with 759 additions and 230 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Function;
import java.util.function.Supplier;

/**
* Once created, an {@link InjectEnvironment} is immutable and thread safe. Values returned by {@link #get(Class)} should be immutable and thread safe,
Expand Down Expand Up @@ -57,6 +59,16 @@ public <T> Builder add(Class<? super T> clazz, T object) {
map.put(clazz, object);
return this;
}
public <T> Builder update(Class<T> clazz, Function<T, T> updateFunction, Supplier<T> createFunction) {
// TODO do we want to use java.util.function here? Do we care about Android compatibility?
T current = clazz.cast(map.get(clazz));
if (current == null) {
current = createFunction.get();
}
current = updateFunction.apply(current);
map.put(clazz, current);
return this;
}
public InjectEnvironment build() {
return new InjectEnvironment(map);
}
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ subprojects {
disable("UnusedVariable") // We are OK with this most of the time
disable("CanonicalDuration") // I will specify my durations in whatever units I please

error("MissingOverride")

// Experimental Errors
enable("ClassName")
warn("DepAnn")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package me.retrodaredevil.solarthing.actions.command;

import me.retrodaredevil.solarthing.type.open.OpenSource;
import me.retrodaredevil.action.node.environment.InjectEnvironment;
import me.retrodaredevil.solarthing.reason.ExecutionReason;

public interface EnvironmentUpdater {
void updateInjectEnvironment(OpenSource source, InjectEnvironment.Builder injectEnvironmentBuilder);
void updateInjectEnvironment(ExecutionReason executionReason, InjectEnvironment.Builder injectEnvironmentBuilder);

EnvironmentUpdater DO_NOTHING = (dataSource, injectEnvironmentBuilder) -> {};
EnvironmentUpdater DO_NOTHING = (_executionReason, _injectEnvironmentBuilder) -> {};
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package me.retrodaredevil.solarthing.actions.command;

import me.retrodaredevil.solarthing.type.open.OpenSource;
import me.retrodaredevil.action.node.environment.InjectEnvironment;
import me.retrodaredevil.solarthing.reason.ExecutionReason;

import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class EnvironmentUpdaterMultiplexer implements EnvironmentUpdater {
private final List<EnvironmentUpdater> environmentUpdaterList;
Expand All @@ -16,9 +20,9 @@ public EnvironmentUpdaterMultiplexer(EnvironmentUpdater... environmentUpdaters)
}

@Override
public void updateInjectEnvironment(OpenSource source, InjectEnvironment.Builder injectEnvironmentBuilder) {
public void updateInjectEnvironment(ExecutionReason executionReason, InjectEnvironment.Builder injectEnvironmentBuilder) {
for (EnvironmentUpdater environmentUpdater : environmentUpdaterList) {
environmentUpdater.updateInjectEnvironment(source, injectEnvironmentBuilder);
environmentUpdater.updateInjectEnvironment(executionReason, injectEnvironmentBuilder);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@
import me.retrodaredevil.action.node.ActionNode;
import me.retrodaredevil.action.node.environment.ActionEnvironment;
import me.retrodaredevil.solarthing.actions.environment.EventReceiverEnvironment;
import me.retrodaredevil.solarthing.actions.environment.SourceEnvironment;
import me.retrodaredevil.solarthing.type.event.feedback.ImmutableExecutionFeedbackPacket;
import me.retrodaredevil.solarthing.type.open.OpenSource;
import me.retrodaredevil.solarthing.actions.environment.ExecutionReasonEnvironment;
import me.retrodaredevil.solarthing.packets.Packet;
import me.retrodaredevil.solarthing.program.PacketListReceiverHandler;
import me.retrodaredevil.solarthing.reason.OpenSourceExecutionReason;
import me.retrodaredevil.solarthing.reason.ExecutionReason;
import me.retrodaredevil.solarthing.type.event.feedback.ImmutableExecutionFeedbackPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -39,12 +38,13 @@ public ExecutingCommandFeedbackActionNode(
}
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
SourceEnvironment sourceEnvironment = actionEnvironment.getInjectEnvironment().get(SourceEnvironment.class);
ExecutionReasonEnvironment executionReasonEnvironment = actionEnvironment.getInjectEnvironment().get(ExecutionReasonEnvironment.class);
EventReceiverEnvironment eventReceiverEnvironment = actionEnvironment.getInjectEnvironment().get(EventReceiverEnvironment.class);
OpenSource source = sourceEnvironment.getSource();

ExecutionReason executionReason = executionReasonEnvironment.getExecutionReason();
PacketListReceiverHandler packetListReceiverHandler = eventReceiverEnvironment.getEventPacketListReceiverHandler();

List<Packet> packets = Arrays.asList(new ImmutableExecutionFeedbackPacket(message, category, new OpenSourceExecutionReason(source)));
List<Packet> packets = Arrays.asList(new ImmutableExecutionFeedbackPacket(message, category, executionReason));
return Actions.createRunOnce(() -> {
LOGGER.debug("Going to upload an execution feedback packet.");
Instant now = Instant.now();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package me.retrodaredevil.solarthing.actions.environment;

import me.retrodaredevil.solarthing.annotations.Nullable;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public final class MultiRoverModbusEnvironment {
private final Map<Integer, RoverModbusEnvironment> map;

public MultiRoverModbusEnvironment(Map<Integer, RoverModbusEnvironment> map) {
this.map = Collections.unmodifiableMap(new HashMap<>(map));
}
public MultiRoverModbusEnvironment() {
this.map = Collections.emptyMap();
}

public @Nullable RoverModbusEnvironment getOrNull(int number) {
return map.get(number);
}

public MultiRoverModbusEnvironment plus(MultiRoverModbusEnvironment environment) {
Map<Integer, RoverModbusEnvironment> newMap = new HashMap<>(map);
newMap.putAll(environment.map);
return new MultiRoverModbusEnvironment(newMap);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package me.retrodaredevil.solarthing.actions.environment;


import me.retrodaredevil.solarthing.annotations.Nullable;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public final class MultiTracerModbusEnvironment {
private final Map<Integer, TracerModbusEnvironment> map;

public MultiTracerModbusEnvironment(Map<Integer, TracerModbusEnvironment> map) {
this.map = Collections.unmodifiableMap(new HashMap<>(map));
}
public MultiTracerModbusEnvironment() {
this.map = Collections.emptyMap();
}

public @Nullable TracerModbusEnvironment getOrNull(int number) {
return map.get(number);
}

public MultiTracerModbusEnvironment plus(MultiTracerModbusEnvironment environment) {
Map<Integer, TracerModbusEnvironment> newMap = new HashMap<>(map);
newMap.putAll(environment.map);
return new MultiTracerModbusEnvironment(newMap);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package me.retrodaredevil.solarthing.actions.environment;

import me.retrodaredevil.solarthing.actions.error.ActionErrorState;

public class RoverErrorEnvironment {
private final ActionErrorState actionErrorState;

public RoverErrorEnvironment(ActionErrorState actionErrorState) {
this.actionErrorState = actionErrorState;
}
public RoverErrorEnvironment() {
this(new ActionErrorState());
}

public ActionErrorState getRoverActionErrorState() {
return actionErrorState;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package me.retrodaredevil.solarthing.actions.environment;

import me.retrodaredevil.solarthing.actions.error.ActionErrorState;

public class TracerErrorEnvironment {
private final ActionErrorState actionErrorState;

public TracerErrorEnvironment(ActionErrorState actionErrorState) {
this.actionErrorState = actionErrorState;
}
public TracerErrorEnvironment() {
this(new ActionErrorState());
}

public ActionErrorState getTracerActionErrorState() {
return actionErrorState;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package me.retrodaredevil.solarthing.actions.error;

public final class ActionErrorState {

private int errorCount = 0;
private int successCount = 0;

public int getErrorCount() {
return errorCount;
}
public void incrementErrorCount() {
errorCount++;
}

public int getSuccessCount() {
return successCount;
}
public void incrementSuccessCount() {
successCount++;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package me.retrodaredevil.solarthing.actions.error;

import me.retrodaredevil.action.Action;
import me.retrodaredevil.action.LinkedAction;
import me.retrodaredevil.action.SimpleAction;

import java.util.List;

public class TryErrorStateAction extends SimpleAction implements LinkedAction {

private final List<Action> actions;
private final Action successAction;
private final Action errorAction;
private final ActionErrorState actionErrorState;
private int index = 0;
private Action nextAction;

public TryErrorStateAction(List<Action> actions, Action successAction, Action errorAction, ActionErrorState actionErrorState) {
super(false);
this.actions = actions;
this.successAction = successAction;
this.errorAction = errorAction;
this.actionErrorState = actionErrorState;
}

@Override
protected void onUpdate() {
super.onUpdate();

while (true) {
if (index >= actions.size()) { // finished all actions successfully
nextAction = successAction;
setDone(true);
return;
}
Action activeAction = actions.get(index);
activeAction.update();
if (activeAction.isDone()) {
activeAction.end();
index++;
if (actionErrorState.getErrorCount() > 0) { // an error occurred from something and the action that caused it has just finished
nextAction = errorAction;
setDone(true);
return;
}
} else {
break; // continue next iteration. This action is not done
}
}
}

@Override
public Action getNextAction() {
return nextAction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import com.fasterxml.jackson.annotation.JsonTypeName;
import me.retrodaredevil.action.Action;
import me.retrodaredevil.action.Actions;
import me.retrodaredevil.solarthing.type.open.OpenSource;
import me.retrodaredevil.action.node.ActionNode;
import me.retrodaredevil.action.node.environment.ActionEnvironment;
import me.retrodaredevil.solarthing.actions.environment.ExecutionReasonEnvironment;
import me.retrodaredevil.solarthing.actions.environment.MateCommandEnvironment;
import me.retrodaredevil.solarthing.actions.environment.SourceEnvironment;
import me.retrodaredevil.solarthing.commands.command.SourcedCommand;
import me.retrodaredevil.solarthing.reason.ExecutionReason;
import me.retrodaredevil.solarthing.solar.outback.command.MateCommand;

import java.util.Queue;
Expand All @@ -26,9 +26,10 @@ public MateCommandActionNode(@JsonProperty("command") MateCommand mateCommand) {
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
MateCommandEnvironment mateCommandEnvironment = actionEnvironment.getInjectEnvironment().get(MateCommandEnvironment.class);
SourceEnvironment sourceEnvironment = actionEnvironment.getInjectEnvironment().get(SourceEnvironment.class);
ExecutionReasonEnvironment executionReasonEnvironment = actionEnvironment.getInjectEnvironment().get(ExecutionReasonEnvironment.class);

Queue<? super SourcedCommand<MateCommand>> queue = mateCommandEnvironment.getQueue();
OpenSource source = sourceEnvironment.getSource();
return Actions.createRunOnce(() -> queue.add(new SourcedCommand<>(source, mateCommand)));
ExecutionReason executionReason = executionReasonEnvironment.getExecutionReason();
return Actions.createRunOnce(() -> queue.add(new SourcedCommand<>(executionReason, mateCommand)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import me.retrodaredevil.solarthing.SolarThingConstants;
import me.retrodaredevil.action.node.ActionNode;
import me.retrodaredevil.action.node.environment.ActionEnvironment;
import me.retrodaredevil.solarthing.actions.environment.RoverErrorEnvironment;
import me.retrodaredevil.solarthing.actions.environment.RoverModbusEnvironment;
import me.retrodaredevil.solarthing.actions.error.ActionErrorState;
import me.retrodaredevil.solarthing.solar.renogy.rover.RoverWriteTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -31,7 +33,11 @@ public RoverBoostSetActionNode(@JsonProperty("voltageraw") Integer boostVoltageR
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
RoverModbusEnvironment environment = actionEnvironment.getInjectEnvironment().get(RoverModbusEnvironment.class);
RoverErrorEnvironment errorEnvironment = actionEnvironment.getInjectEnvironment().getOrNull(RoverErrorEnvironment.class); // This will only be null when using deprecated attach to commands

RoverWriteTable write = environment.getWrite();
ActionErrorState actionErrorState = errorEnvironment == null ? null : errorEnvironment.getRoverActionErrorState();

return Actions.createRunOnce(() -> {
try {
// TODO have a packet for reporting this to solarthing_events
Expand All @@ -41,9 +47,15 @@ public Action createAction(ActionEnvironment actionEnvironment) {
if (boostTimeMinutes != null) {
write.setBoostChargingTimeMinutes(boostTimeMinutes);
}
if (actionErrorState != null) {
actionErrorState.incrementSuccessCount();
}
LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Successfully executed changed boost parameters.");
} catch (ModbusRuntimeException e) {
LOGGER.error("Unable to perform Modbus request", e);
if (actionErrorState != null) {
actionErrorState.incrementErrorCount();
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Deprecated
@JsonTypeName("roverboostvoltage")
public class RoverBoostVoltageActionNode implements ActionNode {
private static final Logger LOGGER = LoggerFactory.getLogger(RoverBoostVoltageActionNode.class);
Expand All @@ -33,7 +34,6 @@ public RoverBoostVoltageActionNode(
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
RoverMatcher.Provider provider = roverMatcher.createProvider(actionEnvironment.getInjectEnvironment());
provider.validateData();
return new SimpleAction(false) {
@Override
protected void onUpdate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import me.retrodaredevil.solarthing.SolarThingConstants;
import me.retrodaredevil.action.node.ActionNode;
import me.retrodaredevil.action.node.environment.ActionEnvironment;
import me.retrodaredevil.solarthing.actions.environment.RoverErrorEnvironment;
import me.retrodaredevil.solarthing.actions.environment.RoverModbusEnvironment;
import me.retrodaredevil.solarthing.actions.error.ActionErrorState;
import me.retrodaredevil.solarthing.solar.renogy.rover.LoadWorkingMode;
import me.retrodaredevil.solarthing.solar.renogy.rover.RoverWriteTable;
import me.retrodaredevil.solarthing.solar.renogy.rover.StreetLight;
Expand All @@ -29,14 +31,19 @@ public RoverLoadActionNode(@JsonProperty(value = "on", required = true) boolean
@Override
public Action createAction(ActionEnvironment actionEnvironment) {
RoverModbusEnvironment environment = actionEnvironment.getInjectEnvironment().get(RoverModbusEnvironment.class);
RoverErrorEnvironment errorEnvironment = actionEnvironment.getInjectEnvironment().get(RoverErrorEnvironment.class);

RoverWriteTable write = environment.getWrite();
ActionErrorState errorState = errorEnvironment.getRoverActionErrorState();
return Actions.createRunOnce(() -> {
try {
write.setLoadWorkingMode(LoadWorkingMode.MANUAL);
write.setStreetLightStatus(on ? StreetLight.ON : StreetLight.OFF);
LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Successfully executed load command. on: " + on);
errorState.incrementSuccessCount();
} catch (ModbusRuntimeException e) {
LOGGER.error("Unable to perform Modbus request", e);
errorState.incrementErrorCount();
}
});
}
Expand Down
Loading

0 comments on commit d45605c

Please sign in to comment.