Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

How to get value from the two source points?


  • Hi,
    In our Mango system we should change the value of the target point based on the value of the two source points. We should show the alarm message in the public view to the end user immidiately after the value is over the low limit.
    We try to use point linking, but we need to also get the current value of two source points (source2.value) to change the target value.

    if (source.value > source2.value) return true; return false;
    // source is measured humidity value
    // source2 is static value set by the Mango user as a low limit to Alarm
    

    We try to use "Point Linking", but It's not possible to use two source points there?
    Any other hints how to implement this?


  • Use a meta point to combine the values of the two points into one. Then add your detectors and handlers to the meta point.


  • Hi,
    I need to get the timestamp value of a point and compare it with another time period value, saved in another point value.
    Is this possible using a meta point..? e.g. "if (p100.time > p99.value) return something;"

    Regards,
    Petteri


  • Hi Petteri,

    This was missing, but is added now and in for the next release. I've added typical date related functions including things like this:

    p.time --&gt returns the timestamp of the value in milliseconds since the epoch
    p.millis --&gt 0-999 the millisecond portion of p.time
    p.second --&gt 0-60
    p.minute --&gt 0-60
    p.hour --&gt 0-23
    p.day --&gt 1-28,31
    p.dayOfWeek --&gt 1-7 where 1 is Sunday
    p.dayOfYear --&gt 1-365,366
    p.month --&gt 1-12
    p.year --&gt four digits


  • @mlohbihler said:

    I've added typical date related functions including things like this:

    p.time --&gt returns the timestamp of the value in milliseconds since the epoch

    I've got a patch that allows the timestamp of a meta point to be set. This is useful when data is being read from a table and some point values are the date & time for the rest of the data in the row.


  • How does it work? A separate script?


  • Patch below adds a logging type for when a point's timestamp changes and reads the TIMESTAMP variable from the meta point script engine and sets the point's timestamp to TIMESTAMP if TIMESTAMP is set.

    This part of reading data tables is working fine. controlling the row pointer with point detectors and event handlers works OK but eventually gets hung up after some kind of exception.

    === modified file 'src/com/serotonin/mango/rt/dataImage/DataPointRT.java'
    --- src/com/serotonin/mango/rt/dataImage/DataPointRT.java       2009-10-20 21:08:00 +0000
    +++ src/com/serotonin/mango/rt/dataImage/DataPointRT.java       2009-10-21 03:04:37 +0000
    @@ -200,6 +200,17 @@
             case DataPointVO.LoggingTypes.ALL :
                 logValue = true;
                 break;
    +        case DataPointVO.LoggingTypes.ON_TS_CHANGE :
    +               if (pointValue == null) 
    +                       logValue = true;
    +               else {
    +                       if (newValue.getTime() != pointValue.getTime())
    +                               logValue = true;
    +                       else
    +                               logValue = false;
    +               }
    +               saveValue = logValue;
    +               break;
             case DataPointVO.LoggingTypes.INTERVAL :
                 intervalSave(newValue);
             default :
    
    === modified file 'src/com/serotonin/mango/rt/dataSource/meta/MetaPointLocatorRT.java'
    --- src/com/serotonin/mango/rt/dataSource/meta/MetaPointLocatorRT.java  2009-10-20 21:08:00 +0000
    +++ src/com/serotonin/mango/rt/dataSource/meta/MetaPointLocatorRT.java  2009-10-21 03:04:37 +0000
    @@ -237,7 +237,10 @@
                     if (result == null)
                         dataSource.raiseScriptError(runtime, dataPoint, new LocalizableMessage("event.meta.nullResult"));
                     else
    -                    dataPoint.updatePointValue(new PointValueTime(result, runtime));
    +                       if (result instanceof PointValueTime)
    +                               dataPoint.updatePointValue((PointValueTime)result);
    +                       else 
    +                               dataPoint.updatePointValue(new PointValueTime(result, runtime));
                 }
                 catch (ScriptException e) {
                     dataSource.raiseScriptError(runtime, dataPoint, new LocalizableMessage("common.default",
    
    === modified file 'src/com/serotonin/mango/rt/dataSource/meta/ScriptExecutor.java'
    --- src/com/serotonin/mango/rt/dataSource/meta/ScriptExecutor.java      2009-10-20 21:08:00 +0000
    +++ src/com/serotonin/mango/rt/dataSource/meta/ScriptExecutor.java      2009-10-21 03:04:37 +0000
    @@ -38,6 +38,7 @@
     import com.serotonin.mango.rt.RuntimeManager;
     import com.serotonin.mango.rt.dataImage.DataPointRT;
     import com.serotonin.mango.rt.dataImage.IDataPoint;
    +import com.serotonin.mango.rt.dataImage.PointValueTime;
     import com.serotonin.web.i18n.LocalizableMessage;
     
     /**
    @@ -84,6 +85,25 @@
                 return null;
             }
             
    +        // i've changed things so we may have a pointvalue time with
    +        // an obj and a ts. need to return a PVT here with obj cast correctly.
    +        if (result instanceof PointValueTime) {
    +        	PointValueTime pvt = (PointValueTime)result;
    +        	Object value = pvt.getValue();
    +        	long timestamp = pvt.getTime();
    +        	
    +            // See if the type matches.
    +            if (dataTypeId == DataTypes.BINARY && value instanceof Boolean)
    +                return new PointValueTime(value, timestamp);
    +            if (dataTypeId == DataTypes.MULTISTATE && value instanceof Number)
    +                return new PointValueTime(((Number)value).intValue(), timestamp);
    +            if (dataTypeId == DataTypes.NUMERIC && value instanceof Number)
    +                return new PointValueTime(((Number)value).doubleValue(), timestamp);
    +            if (dataTypeId == DataTypes.ALPHANUMERIC && value instanceof String)
    +                return new PointValueTime(value, timestamp);
    +        }
    +        
    +        
             // See if the type matches.
             if (dataTypeId == DataTypes.BINARY && result instanceof Boolean)
                 return result;
    @@ -120,6 +140,9 @@
             engine.put("MONTH", Common.TimePeriods.MONTHS);
             engine.put("YEAR", Common.TimePeriods.YEARS);
             
    +        // a variable to put the script-generated timestamp in.
    +        engine.put("TIMESTAMP", null);
    +        
             // Put the context variables into the engine with engine scope.
             for (String varName : context.keySet()) {
                 IDataPoint point = context.get(varName);
    @@ -151,6 +174,11 @@
             if (result instanceof AbstractPointWrapper)
                 result = ((AbstractPointWrapper)result).getValueImpl();
             
    +        Object ts = engine.get("TIMESTAMP");
    +        if (ts != null && ts instanceof Number) {
    +        	return new PointValueTime(result, ((Number)ts).longValue() );
    +        }
    +        
             return result;
         }
         
    
    === modified file 'src/com/serotonin/mango/vo/DataPointVO.java'
    --- src/com/serotonin/mango/vo/DataPointVO.java	2009-10-20 21:08:00 +0000
    +++ src/com/serotonin/mango/vo/DataPointVO.java	2009-10-21 03:04:37 +0000
    @@ -64,6 +64,7 @@
             int ALL = 2;
             int NONE = 3;
             int INTERVAL = 4;
    +        int ON_TS_CHANGE = 10;
         }
         private static final ExportCodes LOGGING_TYPE_CODES = new ExportCodes();
         static {
    @@ -71,6 +72,7 @@
             LOGGING_TYPE_CODES.addElement(LoggingTypes.ALL, "ALL", "pointEdit.logging.type.all");
             LOGGING_TYPE_CODES.addElement(LoggingTypes.NONE, "NONE", "pointEdit.logging.type.never");
             LOGGING_TYPE_CODES.addElement(LoggingTypes.INTERVAL, "INTERVAL", "pointEdit.logging.type.interval");
    +        LOGGING_TYPE_CODES.addElement(LoggingTypes.ON_TS_CHANGE, "TIMESTAMP", "pointEdit.logging.type.timestamp");
         }
         
         public interface PurgeTypes {
    
    === modified file 'src/com/serotonin/mango/web/mvc/controller/DataPointEditController.java'
    --- src/com/serotonin/mango/web/mvc/controller/DataPointEditController.java	2009-10-20 21:08:00 +0000
    +++ src/com/serotonin/mango/web/mvc/controller/DataPointEditController.java	2009-10-21 03:04:37 +0000
    @@ -128,7 +128,8 @@
             if (point.getLoggingType() != DataPointVO.LoggingTypes.ON_CHANGE && 
                     point.getLoggingType() != DataPointVO.LoggingTypes.ALL &&
                     point.getLoggingType() != DataPointVO.LoggingTypes.NONE &&
    -                point.getLoggingType() != DataPointVO.LoggingTypes.INTERVAL)
    +                point.getLoggingType() != DataPointVO.LoggingTypes.INTERVAL &&
    +                point.getLoggingType() != DataPointVO.LoggingTypes.ON_TS_CHANGE)
                 ValidationUtils.rejectValue(errors, "loggingType", "validate.required");
             
             if (point.getLoggingType() == DataPointVO.LoggingTypes.INTERVAL) {
    
    === modified file 'war/WEB-INF/classes/messages_en.properties'
    --- war/WEB-INF/classes/messages_en.properties	2009-10-20 21:08:00 +0000
    +++ war/WEB-INF/classes/messages_en.properties	2009-10-21 03:04:37 +0000
    @@ -1144,6 +1144,7 @@
     pointEdit.logging.type.all=All data
     pointEdit.logging.type.never=Do not log
     pointEdit.logging.type.interval=Interval
    +pointEdit.logging.type.ts_change=When point timestamp changes
     pointEdit.logging.period=Interval logging period
     pointEdit.logging.every=Every
     pointEdit.logging.valueType=Value type
    
    === modified file 'war/WEB-INF/jsp/pointEdit/loggingProperties.jsp'
    --- war/WEB-INF/jsp/pointEdit/loggingProperties.jsp	2009-10-20 21:08:00 +0000
    +++ war/WEB-INF/jsp/pointEdit/loggingProperties.jsp	2009-10-21 03:04:37 +0000
    @@ -33,7 +33,8 @@
           else
               tolerance.disabled = true;
           
    -      if (loggingType == <%= DataPointVO.LoggingTypes.NONE %>) {
    +      if (loggingType == <%= DataPointVO.LoggingTypes.NONE %> || 
    +          loggingType == <%= DataPointVO.LoggingTypes.ON_TS_CHANGE %> ) {
               purgePeriod.disabled = true;
               purgeType.disabled = true;
           }
    @@ -75,6 +76,7 @@
                 <sst:option value="<%= Integer.toString(DataPointVO.LoggingTypes.ALL) %>"><fmt:message key="pointEdit.logging.type.all"/></sst:option>
                 <sst:option value="<%= Integer.toString(DataPointVO.LoggingTypes.NONE) %>"><fmt:message key="pointEdit.logging.type.never"/></sst:option>
                 <sst:option value="<%= Integer.toString(DataPointVO.LoggingTypes.INTERVAL) %>"><fmt:message key="pointEdit.logging.type.interval"/></sst:option>
    +            <sst:option value="<%= Integer.toString(DataPointVO.LoggingTypes.ON_TS_CHANGE) %>"><fmt:message key="pointEdit.logging.type.ts_change"/></sst:option>
               </sst:select>
             </td>
             <td class="formError">${status.errorMessage}</td>
    
    

  • Hi Craig,

    I ported this code into the next Mango release with a couple of minor changes.

    1. The message properties key for the new logging type is "pointEdit.logging.type.tsChange".
    2. The ScriptExecutor methods now return a PointValueTime object, rather than an Object. The two methods with similar signatures have been combined.

  • P.S. thanks again for contributing. You rock.