[ 
https://issues.apache.org/jira/browse/CAMEL-18861?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17679693#comment-17679693
 ] 

Stein Overtoom commented on CAMEL-18861:
----------------------------------------

I could use some help with the last improvement I want to make.

 
I'm using the component to poll certain modbus coils every x seconds. The 
problem is that the polling is done via a future called by the doStart() method 
that is only executed once. Right now I'm using a workaround where I created a 
PollingConsumer in a processor that is started and stopped for every request 
(and the processor is called by the TimerComponent every x seconds).
For completeness here is the code:
{code:java}
from(String.format(“timer://%s?fixedRate=true&period=%d”, “timer-name”, 10))
        .process(processor)
        // Some logic which handles the result {code}
Camel route:
{code:java}
@Override
public void process(Exchange exchange) throws Exception {
    Plc4XEndpoint plcEndpoint = (Plc4XEndpoint) 
getCamelContext().getEndpoint(properties.getModbusUri());

    if (pollingConsumer == null) {
        pollingConsumer = plcEndpoint.createPollingConsumer();
    }
    pollingConsumer.start();
    Exchange ex = pollingConsumer.receive(5000);
    if (ex == null) {
        log.error(“Response timed out”);
        exchange.getIn().setBody(new HashMap<String, Object>());
    } else {
        exchange.getIn().setBody(ex.getIn().getBody());
    }
    pollingConsumer.stop();
} {code}
This feels a bit like hacking and I think that timed polling is a feature that 
more people would find useful. Also, the component documentation says the 
following: "The consumer supports one-time reading or Triggered Reading. 
({_}Schedulded Reading using Period only soon{_})." I think this means that 
this feature was meant to be added later, but no one ever got to it (the last 
update to the docs is from 2020, not counting the transfer from the plc4x repo 
to the camel repo).
 
*Now to the part I need help with:*
I'm want to implement timed polling for the Plc4XConsumer so an interval can be 
specified at which the consumer polls the specified tags (in my case some 
modbus coils). But I'm not sure what would be a clean and "Camel-like" 
implementation. I was thinking about modifying the current startUnTriggered 
method to use a ScheduledExecutorService#scheduleAtFixedRate future, see the 
code below.
The interval could be passed to the already existing "Period" option. To use 
the timed polling could be configured by passing "timed" to the already 
existing "Trigger" option.
{code:java}
private void startUnTriggeredOrTimed(boolean timed) {
    if (plc4XEndpoint.isAutoReconnect() && !plcConnection.isConnected()) {
        try {
            plc4XEndpoint.reconnect();
            LOGGER.debug(“Successfully reconnected”);
        } catch (PlcConnectionException e) {
            LOGGER.warn(“Unable to reconnect, skipping request”, e);
            return;
        }
    }
    PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
    for (Map.Entry<String, Object> tag : tags.entrySet()) {
        try {
            builder.addItem(tag.getKey(), (String) tag.getValue());
        } catch (PlcIncompatibleDatatypeException e) {
            LOGGER.error(“For consumer, please use Map<String,String>, 
currently using {}”, tags.getClass().getSimpleName());
        }
    }
    PlcReadRequest request = builder.build();
    Runnable runnable = () ->
        request.execute().thenAccept(response -> {
            try {
                Exchange exchange = plc4XEndpoint.createExchange();
                Map<String, Object> rsp = new HashMap<>();
                for (String field : response.getFieldNames()) {
                    rsp.put(field, response.getObject(field));
                }
                exchange.getIn().setBody(rsp);
                getProcessor().process(exchange);
            } catch (Exception e) {
                getExceptionHandler().handleException(e);
            }
        });
    if (timed) {
        future = executorService.scheduleAtFixedRate(runnable, 500, 
plc4XEndpoint.getPeriod(), TimeUnit.MILLISECONDS);
    } else {
        future = executorService.schedule(runnable, 500, TimeUnit.MILLISECONDS);
    }
} {code}
{code:java}
@Override
protected void doStart() throws Exception {
    super.doStart();
    this.plcConnection = plc4XEndpoint.getConnection();
    if (!plcConnection.isConnected()) {
        plc4XEndpoint.reconnect();
    }
    boolean timed = trigger != null && trigger.equalsIgnoreCase(“timed”);
    if (trigger == null || timed) {
        startUnTriggeredOrTimed(timed);
    } else {
        startTriggered();
    }
} {code}
Another thing I should note, I couldn't figure out how exactly the triggered 
reading works (I think it's supposed to poll when, for example, a modbus coil 
changes its value). I tried mailing the plc4x mailing list, but I didn't get a 
response.  I did speak with Christopher Dutz (the main contributor there), but 
he also did not know how the triggered reading works.
 
I would appreciate some input!
 
Yours,
Stein
 
 

> Improving PLC4X component
> -------------------------
>
>                 Key: CAMEL-18861
>                 URL: https://issues.apache.org/jira/browse/CAMEL-18861
>             Project: Camel
>          Issue Type: Improvement
>    Affects Versions: 3.20.0
>            Reporter: Stein Overtoom
>            Priority: Major
>              Labels: plc4x
>             Fix For: 3.21.0
>
>
> This ticket is for a collection of improvements to the plc4x component.
>  * Move connection establishment from constructor to doStart() method 
> ([done|https://github.com/apache/camel/pull/8967])
>  * Fix completableFuture without timeout in Plc4XProducer 
> ([done|https://github.com/apache/camel/pull/8968])
>  * Change deprecated methods in Plc4XProducer for non-deprecated ones 
> ([done|https://github.com/apache/camel/pull/8968])
>  * Add autoReconnect uri parameter 
> ([done|https://github.com/apache/camel/pull/8971])
>  * Fix Plc4XComponentTest unit test inconsistently failing/succeeding
>  * Add option for repeated polling (not sure yet if not already supported, 
> see also: [this plc4x feature 
> request|https://github.com/apache/plc4x/issues/716]



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to