Simple Query Through Store & Forward

How would I go about sending a simple insert command (or list of insert commands) through the Ignition S&F system in the Module SDK? I’m looking for something like the IA Labs “runSFPrepUpdate” Jython call.

That call is implemented via HistoryManager::storeHistory, which you can get to from the GatewayContext.

More info: that method expects a datasource name and a HistoricalData object.

The simple implementation used by the scripting function looks like this:

    public static class QuerySFData implements DatasourceData {

        private static final long serialVersionUID = 1L;

        String query;
        String datasource;
        Object[] values;

        public QuerySFData(String query, String datasource) {
            this(query, null, datasource);
        }

        public QuerySFData(String query, Object[] values, String datasource) {
            this.query = query;
            this.values = values;
            this.datasource = datasource;
        }

        @Override
        public int getDataCount() {
            return 1;
        }

        @Override
        public HistoryFlavor getFlavor() {
            return DatasourceData.FLAVOR;
        }

        @Override
        public String getLoggerName() {
            return "Client Store & Forward";
        }

        @Override
        public String getSignature() {
            return "Scripted SF Query";
        }

        @Override
        public void storeToConnection(SRConnection conn) throws Exception {
            if (values != null) {
                conn.runPrepUpdate(query, values);
            } else {
                conn.runUpdateQuery(query);
            }
        }

    }
1 Like

Awesome thanks!

Kevin,

Do you have and example of how to send alarm events through store and forward?

We’re pointing at Kafka and I can make tags work with/without S&F and alarms work w/o S&F but when trying to get alarms to go through S&F I’m struggling, I suspect because it’s expecting a different type than I’m providing.

Edited

Specifically I have a class Sink Data which implements HistoricalData like this:

public class SinkData implements HistoricalData {

    private String topic, value, signature;

    public SinkData(String topic, String value,  String signature) {
        this.topic = topic;
        this.value = value;
        this.signature = signature;
    }

I put together the alarm data and call the function like this:

       try {
                String json = new JSONObject()
                        .put("type", "alarm")
                        .put("uuid", alarm.getId().toString())
                        .put("gatewayName", this.hostName)
                        .put("tagPath", src.replace("prov:", "[").replace(":/tag:", "]"))
                        .put("displayPath", path)
                        .put("priority", alarm.getPriority().ordinal())
                        .put("eventType", alarm.getState().ordinal())
                        .put("eventData", String.valueOf(data.getRawValueMap()))
                        .put("eventFlags", alarm.getLastEventState().ordinal())
                        .put("timestamp", data.getTimestamp())
                        .toString();
                SinkData toSend = new SinkData(alarmTopic, json, alarmSignature);
                sendKafkaData(toSend);
            } 

Finally it leads here where the call to storeHistory is made:

public int sendWithHistoryManager(String sinkName, SinkData data) throws Exception {
        try {
            this.historyManager.storeHistory(sinkName, data);
        } catch (Exception e) {
            logger.error("Error sending with history manager: " + e.getCause());
        }
        return 0;
    }

The specific error I am trying to overcome is:

java.lang.ClassCastException: Cannot cast com.inductiveautomation.ignition.gateway.sqltags.model.BasicScanclassHistorySet to com.walmart.kafka.gateway.datasink.SinkData

Thanks,

Nick