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 --> returns the timestamp of the value in milliseconds since the epoch
p.millis --> 0-999 the millisecond portion of p.time
p.second --> 0-60
p.minute --> 0-60
p.hour --> 0-23
p.day --> 1-28,31
p.dayOfWeek --> 1-7 where 1 is Sunday
p.dayOfYear --> 1-365,366
p.month --> 1-12
p.year --> four digits -
@mlohbihler said:
I've added typical date related functions including things like this:
p.time --> 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.
- The message properties key for the new logging type is "pointEdit.logging.type.tsChange".
- 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.