Search in sources :

Example 1 with NanoTimeProviderEnvironment

use of me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment in project solarthing by wildmountainfarms.

the class PacketHandlerInit method initHandlers.

public static <T extends PacketHandlingOption & CommandOption> Result initHandlers(T options, Supplier<? extends EnvironmentUpdater> environmentUpdaterSupplier, Collection<? extends PacketHandler> additionalPacketHandlers) throws IOException {
    List<DatabaseConfig> databaseConfigs = ConfigUtil.getDatabaseConfigs(options);
    PacketHandlerBundle packetHandlerBundle = PacketHandlerInit.getPacketHandlerBundle(databaseConfigs, SolarThingConstants.STATUS_DATABASE, SolarThingConstants.EVENT_DATABASE, options.getSourceId(), options.getFragmentId());
    List<PacketHandler> statusPacketHandlers = new ArrayList<>();
    final Runnable updateCommandActions;
    if (options.hasCommands()) {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Command are enabled!");
        // this is used to determine the state of the system when a command is requested
        LatestPacketHandler latestPacketHandler = new LatestPacketHandler();
        statusPacketHandlers.add(latestPacketHandler);
        Map<String, ActionNode> actionNodeMap = ActionUtil.getActionNodeMap(CONFIG_MAPPER, options);
        ActionNodeDataReceiver commandReceiver = new ActionNodeDataReceiver(actionNodeMap, (source, injectEnvironmentBuilder) -> {
            injectEnvironmentBuilder.add(new NanoTimeProviderEnvironment(NanoTimeProvider.SYSTEM_NANO_TIME)).add(new TimeZoneEnvironment(options.getZoneId())).add(new LatestPacketGroupEnvironment(latestPacketHandler::getLatestPacketCollection)).add(new SourceEnvironment(source)).add(new EventReceiverEnvironment(PacketListReceiverHandlerBundle.createEventPacketListReceiverHandler(SolarMain.getSourceAndFragmentUpdater(options), options.getZoneId(), packetHandlerBundle)));
            EnvironmentUpdater environmentUpdater = environmentUpdaterSupplier.get();
            if (environmentUpdater == null) {
                throw new NullPointerException("The EnvironmentUpdater supplier gave a null value! (Fatal)");
            }
            environmentUpdater.updateInjectEnvironment(source, injectEnvironmentBuilder);
        });
        PacketGroupReceiver mainPacketGroupReceiver = new PacketGroupReceiverMultiplexer(Arrays.asList(commandReceiver, new RequestHeartbeatReceiver(PacketListReceiverHandlerBundle.createEventPacketListReceiverHandler(SolarMain.getSourceAndFragmentUpdater(options), options.getZoneId(), packetHandlerBundle))));
        statusPacketHandlers.add((packetCollection) -> commandReceiver.getActionUpdater().update());
        List<PacketHandler> commandPacketHandlers = CommandUtil.getCommandRequesterHandlerList(databaseConfigs, mainPacketGroupReceiver, options);
        statusPacketHandlers.add(new PacketHandlerMultiplexer(commandPacketHandlers));
        updateCommandActions = () -> commandReceiver.getActionUpdater().update();
    } else {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Commands are disabled");
        updateCommandActions = () -> {
        };
    }
    statusPacketHandlers.addAll(additionalPacketHandlers);
    statusPacketHandlers.addAll(packetHandlerBundle.getStatusPacketHandlers());
    PacketListReceiverHandlerBundle bundle = PacketListReceiverHandlerBundle.createFrom(options, packetHandlerBundle, statusPacketHandlers);
    return new Result(bundle, updateCommandActions);
}
Also used : TimeZoneEnvironment(me.retrodaredevil.solarthing.actions.environment.TimeZoneEnvironment) EventReceiverEnvironment(me.retrodaredevil.solarthing.actions.environment.EventReceiverEnvironment) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) LatestPacketGroupEnvironment(me.retrodaredevil.solarthing.actions.environment.LatestPacketGroupEnvironment) PacketGroupReceiver(me.retrodaredevil.solarthing.PacketGroupReceiver) ArrayList(java.util.ArrayList) ActionNode(me.retrodaredevil.action.node.ActionNode) RequestHeartbeatReceiver(me.retrodaredevil.solarthing.program.receiver.RequestHeartbeatReceiver) PacketGroupReceiverMultiplexer(me.retrodaredevil.solarthing.PacketGroupReceiverMultiplexer) EnvironmentUpdater(me.retrodaredevil.solarthing.actions.command.EnvironmentUpdater) SourceEnvironment(me.retrodaredevil.solarthing.actions.environment.SourceEnvironment) FileWritePacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.FileWritePacketHandler) PostPacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.PostPacketHandler) JacksonStringPacketHandler(me.retrodaredevil.solarthing.packets.handling.implementations.JacksonStringPacketHandler) ActionNodeDataReceiver(me.retrodaredevil.solarthing.program.receiver.ActionNodeDataReceiver)

Example 2 with NanoTimeProviderEnvironment

use of me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment in project solarthing by wildmountainfarms.

the class CommandHandler method createInjectEnvironment.

public InjectEnvironment createInjectEnvironment(String commandName) {
    var builder = new InjectEnvironment.Builder().add(new NanoTimeProviderEnvironment(NanoTimeProvider.SYSTEM_NANO_TIME)).add(new SolarThingDatabaseEnvironment(solarThingDatabase)).add(new TimeZoneEnvironment(zoneId));
    RestCommandConfig.Command command = restCommandConfig.getCommandToActionFileMap().get(commandName);
    if (command == null) {
        throw new IllegalStateException("You should not be calling createInjectEnvironment if the command doesn't exist for commandName: " + commandName);
    }
    String sourceId = command.getSourceId();
    if (sourceId != null) {
        builder.add(new SourceIdEnvironment(sourceId));
    }
    return builder.build();
}
Also used : SolarThingDatabaseEnvironment(me.retrodaredevil.solarthing.actions.environment.SolarThingDatabaseEnvironment) SourceIdEnvironment(me.retrodaredevil.solarthing.actions.environment.SourceIdEnvironment) TimeZoneEnvironment(me.retrodaredevil.solarthing.actions.environment.TimeZoneEnvironment) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment)

Example 3 with NanoTimeProviderEnvironment

use of me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment in project solarthing by wildmountainfarms.

the class AutomationMain method startAutomation.

public static int startAutomation(List<ActionNode> actionNodes, DatabaseTimeZoneOptionBase options, long periodMillis) {
    LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Starting automation program.");
    final CouchDbDatabaseSettings couchSettings;
    try {
        couchSettings = ConfigUtil.expectCouchDbDatabaseSettings(options);
    } catch (IllegalArgumentException ex) {
        LOGGER.error("(Fatal)", ex);
        return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
    }
    SolarThingDatabase database = CouchDbSolarThingDatabase.create(CouchDbUtil.createInstance(couchSettings.getCouchProperties(), couchSettings.getOkHttpProperties()));
    VariableEnvironment variableEnvironment = new VariableEnvironment();
    // Use atomic reference so that access is thread safe
    AtomicReference<FragmentedPacketGroup> latestPacketGroupReference = new AtomicReference<>(null);
    // Use atomic reference so that access is thread safe
    AtomicReference<List<VersionedPacket<StoredAlterPacket>>> alterPacketsReference = new AtomicReference<>(null);
    // note this may return null, and that's OK // This is thread safe if needed
    FragmentedPacketGroupProvider fragmentedPacketGroupProvider = latestPacketGroupReference::get;
    Clock clock = Clock.systemUTC();
    SimpleDatabaseCache statusDatabaseCache = SimpleDatabaseCache.createDefault(clock);
    // not thread safe
    ResourceManager<SimpleDatabaseCache> statusDatabaseCacheManager = new BasicResourceManager<>(statusDatabaseCache);
    SimpleDatabaseCache eventDatabaseCache = SimpleDatabaseCache.createDefault(clock);
    ResourceManager<SimpleDatabaseCache> eventDatabaseCacheManager = new ReadWriteResourceManager<>(eventDatabaseCache);
    SimpleDatabaseCache openDatabaseCache = new SimpleDatabaseCache(Duration.ofMinutes(60), Duration.ofMinutes(40), Duration.ofMinutes(20), Duration.ofMinutes(15), clock);
    // not thread safe
    ResourceManager<SimpleDatabaseCache> openDatabaseCacheManager = new BasicResourceManager<>(openDatabaseCache);
    SimplePacketCache<AuthorizationPacket> authorizationPacketCache = new SimplePacketCache<>(Duration.ofSeconds(20), DatabaseDocumentKeyMap.createPacketSourceFromDatabase(database), false);
    String sourceId = options.getSourceId();
    InjectEnvironment injectEnvironment = new InjectEnvironment.Builder().add(new NanoTimeProviderEnvironment(NanoTimeProvider.SYSTEM_NANO_TIME)).add(new SourceIdEnvironment(sourceId)).add(// most of the time, it's better to use SolarThingDatabaseEnvironment instead, but this option is here in case it's needed
    new CouchDbEnvironment(couchSettings)).add(new SolarThingDatabaseEnvironment(CouchDbSolarThingDatabase.create(CouchDbUtil.createInstance(couchSettings.getCouchProperties(), couchSettings.getOkHttpProperties())))).add(new TimeZoneEnvironment(options.getZoneId())).add(// access is thread safe if needed
    new LatestPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(// access is thread safe if needed
    new LatestFragmentedPacketGroupEnvironment(fragmentedPacketGroupProvider)).add(new EventDatabaseCacheEnvironment(eventDatabaseCacheManager)).add(new OpenDatabaseCacheEnvironment(openDatabaseCache)).add(// access is thread safe if needed
    new AlterPacketsEnvironment(alterPacketsReference::get)).add(new AuthorizationEnvironment(new DatabaseDocumentKeyMap(authorizationPacketCache))).build();
    ActionMultiplexer multiplexer = new Actions.ActionMultiplexerBuilder().build();
    while (!Thread.currentThread().isInterrupted()) {
        queryAndFeed(database.getStatusDatabase(), statusDatabaseCacheManager, true);
        queryAndFeed(database.getEventDatabase(), eventDatabaseCacheManager, true);
        queryAndFeed(database.getOpenDatabase(), openDatabaseCacheManager, false);
        {
            // Never cache alter packets, because it's always important that we have up-to-date data, or no data at all.
            List<VersionedPacket<StoredAlterPacket>> alterPackets = null;
            try {
                alterPackets = database.getAlterDatabase().queryAll(sourceId);
                LOGGER.debug("Got " + alterPackets.size() + " alter packets");
            } catch (SolarThingDatabaseException e) {
                LOGGER.error("Could not get alter packets", e);
            }
            alterPacketsReference.set(alterPackets);
        }
        // we have auto update turned off, so we have to call this
        authorizationPacketCache.updateIfNeeded();
        List<FragmentedPacketGroup> statusPacketGroups = PacketUtil.getPacketGroups(options.getSourceId(), options.getDefaultInstanceOptions(), statusDatabaseCache.getAllCachedPackets());
        if (statusPacketGroups != null) {
            FragmentedPacketGroup statusPacketGroup = statusPacketGroups.get(statusPacketGroups.size() - 1);
            latestPacketGroupReference.set(statusPacketGroup);
        }
        for (ActionNode actionNode : actionNodes) {
            multiplexer.add(actionNode.createAction(new ActionEnvironment(variableEnvironment, new VariableEnvironment(), injectEnvironment)));
        }
        multiplexer.update();
        LOGGER.debug("There are " + multiplexer.getActiveActions().size() + " active actions");
        try {
            Thread.sleep(periodMillis);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(ex);
        }
    }
    return 0;
}
Also used : ActionEnvironment(me.retrodaredevil.action.node.environment.ActionEnvironment) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) ActionNode(me.retrodaredevil.action.node.ActionNode) BasicResourceManager(me.retrodaredevil.solarthing.util.sync.BasicResourceManager) Clock(java.time.Clock) FragmentedPacketGroupProvider(me.retrodaredevil.solarthing.FragmentedPacketGroupProvider) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment) AuthorizationPacket(me.retrodaredevil.solarthing.type.closed.authorization.AuthorizationPacket) SimpleDatabaseCache(me.retrodaredevil.solarthing.database.cache.SimpleDatabaseCache) SimplePacketCache(me.retrodaredevil.solarthing.database.cache.SimplePacketCache) ArrayList(java.util.ArrayList) List(java.util.List) ActionMultiplexer(me.retrodaredevil.action.ActionMultiplexer) CouchDbSolarThingDatabase(me.retrodaredevil.solarthing.database.couchdb.CouchDbSolarThingDatabase) ReadWriteResourceManager(me.retrodaredevil.solarthing.util.sync.ReadWriteResourceManager) FragmentedPacketGroup(me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) Actions(me.retrodaredevil.action.Actions) AtomicReference(java.util.concurrent.atomic.AtomicReference) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) CouchDbDatabaseSettings(me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings) VariableEnvironment(me.retrodaredevil.action.node.environment.VariableEnvironment)

Example 4 with NanoTimeProviderEnvironment

use of me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment in project solarthing by wildmountainfarms.

the class TimeoutActionNode method createAction.

@Override
public Action createAction(ActionEnvironment actionEnvironment) {
    NanoTimeProviderEnvironment nanoTimeProviderEnvironment = actionEnvironment.getInjectEnvironment().get(NanoTimeProviderEnvironment.class);
    NanoTimeProvider nanoTimeProvider = nanoTimeProviderEnvironment.getNanoTimeProvider();
    return Actions.createDynamicActionRunner(() -> {
        final Long lastFireNanos = this.lastFireNanos;
        long nowNanos = nanoTimeProvider.getNanos();
        if (lastFireNanos == null || nowNanos - lastFireNanos > timeoutNanos) {
            this.lastFireNanos = nowNanos;
            return actionNode.createAction(actionEnvironment);
        }
        return Actions.createRunOnce(() -> {
        });
    });
}
Also used : NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) NanoTimeProvider(me.retrodaredevil.action.node.util.NanoTimeProvider)

Example 5 with NanoTimeProviderEnvironment

use of me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment 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());
    }
}
Also used : FragmentedPacketGroup(me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup) ActionEnvironment(me.retrodaredevil.action.node.environment.ActionEnvironment) Action(me.retrodaredevil.action.Action) NanoTimeProviderEnvironment(me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment) LatestPacketGroupEnvironment(me.retrodaredevil.solarthing.actions.environment.LatestPacketGroupEnvironment) SerialConfigBuilder(me.retrodaredevil.io.serial.SerialConfigBuilder) ActionNode(me.retrodaredevil.action.node.ActionNode) Duration(java.time.Duration) FragmentedPacketGroupProvider(me.retrodaredevil.solarthing.FragmentedPacketGroupProvider) InjectEnvironment(me.retrodaredevil.action.node.environment.InjectEnvironment) LatestFragmentedPacketGroupEnvironment(me.retrodaredevil.solarthing.actions.environment.LatestFragmentedPacketGroupEnvironment) FXStatusPacket(me.retrodaredevil.solarthing.solar.outback.fx.FXStatusPacket) VariableEnvironment(me.retrodaredevil.action.node.environment.VariableEnvironment) File(java.io.File) Test(org.junit.jupiter.api.Test)

Aggregations

NanoTimeProviderEnvironment (me.retrodaredevil.action.node.environment.NanoTimeProviderEnvironment)5 ActionNode (me.retrodaredevil.action.node.ActionNode)3 InjectEnvironment (me.retrodaredevil.action.node.environment.InjectEnvironment)3 ArrayList (java.util.ArrayList)2 ActionEnvironment (me.retrodaredevil.action.node.environment.ActionEnvironment)2 VariableEnvironment (me.retrodaredevil.action.node.environment.VariableEnvironment)2 FragmentedPacketGroupProvider (me.retrodaredevil.solarthing.FragmentedPacketGroupProvider)2 LatestPacketGroupEnvironment (me.retrodaredevil.solarthing.actions.environment.LatestPacketGroupEnvironment)2 TimeZoneEnvironment (me.retrodaredevil.solarthing.actions.environment.TimeZoneEnvironment)2 FragmentedPacketGroup (me.retrodaredevil.solarthing.packets.collection.FragmentedPacketGroup)2 File (java.io.File)1 Clock (java.time.Clock)1 Duration (java.time.Duration)1 List (java.util.List)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Action (me.retrodaredevil.action.Action)1 ActionMultiplexer (me.retrodaredevil.action.ActionMultiplexer)1 Actions (me.retrodaredevil.action.Actions)1 NanoTimeProvider (me.retrodaredevil.action.node.util.NanoTimeProvider)1 SerialConfigBuilder (me.retrodaredevil.io.serial.SerialConfigBuilder)1