Skip to content

Data Transfers

A Data Transfer periodically writes the value of one variable into another. It can copy the live value straight across, or first compute a statistic from the source’s logged history — an hourly counter difference, yesterday’s average, a monthly maximum.

The Data Transfers screen — the transfer list above, the source-to-target rows of the selected transfer below

The screen is a master/detail pair: a transfer at the top, its rows underneath. The transfer carries the schedule; the rows carry what is copied.

This is the distinction everything else follows from. A row is statistical only when both calcType and rangeType are set. If either is empty, the row is a plain copy.

Current-value rowStatistical row
SetcalcType and rangeType both emptycalcType and rangeType both set
ReadsThe source’s live valueThe source’s logged history over the range
Needs logging on the sourceNoYes
RunsEvery periodOn its own recalculation interval (see below)

A live mirror is therefore a row with the calculation fields left empty — not Last Value over Current Hour. The empty row reads the value that is already in memory; the statistical one queries the historian, which is far more work for the same number.

FieldTypeRequiredDescription
nameString (≤100)YesTransfer name
dscString (≤255)NoDescription
periodInteger (ms, ≥100)YesHow often the transfer runs
statRecalcIntervalSecondsInteger (s, ≥10)NoOverrides the recalculation interval of this transfer’s Current * rows
projectIdStringYesOwning project

period is the floor every repeating thing in the product shares: 100 ms.

FieldDescription
sourceVariableIdThe variable read
targetVariableIdThe variable written
calcTypeStatistical calculation (VariableStatCalculationType)
rangeTypeTime range (VariableStatRangeType)
thresholdWrite filter, as a percentage of the source value
deadbandWrite filter, as an absolute difference

Both compare the value about to be written against what the target already holds, and suppress the write when the change is too small to be worth recording. Both are optional; with neither set, every run writes.

  • deadband is absolute: if |target − source| is smaller than it, the write is skipped.
  • threshold is a percentage: the write happens when |target − source| / |source| × 100 reaches it. When the source is 0, the write happens only if the target is not already 0.
  • deadband is checked first, so an absolute floor still suppresses noise around a near-zero source, where a percentage would otherwise let everything through.

They apply only when both values are numeric. A non-numeric value, or a target with no value yet, always writes.

VariableStatCalculationType — 11 values:

TypeMeaning
MinMinimum over the range
MaxMaximum over the range
AvgArithmetic mean
SumSum
CountSample count
First ValueFirst recorded value in the range
Last ValueLast recorded value in the range
Max DifferenceLargest sample-to-sample delta
Last First Differencelast − first — the one for cumulative counters
Middle ValueValue at the temporal midpoint of the range
Median ValueSorted median

VariableStatRangeType — 10 values, Current and Previous across five time scales:

TypeRange
Current HourTop of the hour → now
Previous HourThe whole previous hour
Current DayMidnight → now
Previous DayThe whole previous day
Current WeekWeek start → now
Previous WeekThe whole previous week
Current MonthMonth start → now
Previous MonthThe whole previous month
Current YearYear start → now
Previous YearThe whole previous year

Three things decide where those boundaries actually fall:

  • The server’s time zone. Ranges are cut in the server’s own zone, not the viewer’s.
  • The server’s locale sets which day a week starts on.
  • “Now” is the last complete minute, not the current instant — a Current * range stops there so it never asks the historian for samples that have not been flushed yet.

A statistical row does not query the historian on every period. Results are cached, and the transfer re-applies the cached value in between.

  • A Previous * range closes and never changes again, so it is computed once per period and then served from cache until the cache entry expires.
  • A Current * range is recomputed on an interval of its own:
RangeDefault recalculation interval
Current Hour60 s
Current Day5 min
Current Week30 min
Current Month, Current Year1 h

statRecalcIntervalSeconds on the transfer replaces all of those with one value (minimum 10 s).

The practical consequence: period is not how often a statistic is calculated. A short period makes the transfer re-apply its latest result often — useful when the target feeds a screen and you want the write filter evaluated frequently — but it does not make the number any fresher. To compute more often, lower statRecalcIntervalSeconds, not period.

Current-value rows have no cache and do read the source on every period.

A transfer does nothing until it is scheduled. Status is one of two values, Scheduled or Not Scheduled, and Scheduled means attached to the scheduler, not running right now.

  • The project must be active; scheduling one in a passive project is refused.
  • Deactivating a project cancels its transfers.
  • In a cluster, transfers run on the leader only. Requests taken by another node are forwarded to it, and if leadership moves, the new leader restores the schedule — so a scheduled transfer survives restart and failover.
  • Scheduled transfers appear in Job Monitor under the Data Transfer kind.

A failing transfer writes one line to the server log and one to the project log, naming the cause — not one per run. Further runs failing for the same cause stay quiet; a failure with a different cause is reported as the new fault it is. The first run that succeeds afterwards logs a recovery line saying how many runs failed meanwhile, so silence never has to be read as “fixed”.

One refusal is worth knowing in advance: if a target variable carries an Operation Lock, the whole batch is refused and none of the transfer’s rows are written that run. A transfer cannot supply the lock’s password, so there is no remedy except removing the lock or the row.

Hourly consumption from a cumulative meter

Section titled “Hourly consumption from a cumulative meter”
  • Source: Energy_kWh (cumulative, logged)
  • Target: Hourly_Consumption
  • calcType Last First Difference, rangeType Previous Hour
  • period: 60 000 ms

The range closes at the top of each hour and is computed once; the short period only means the result lands promptly after the hour turns.

  • Source: Temperature_C (logged)
  • Target: DailyAvg_Temperature
  • calcType Avg, rangeType Previous Day
  • period: 300 000 ms

Mirroring a site value into a central project

Section titled “Mirroring a site value into a central project”

Put the transfer in the central project:

  • Source: the site project’s Site1_Power_kW
  • Target: Site1_Power_kW in the central project
  • calcType and rangeType: left empty — this is a live copy
  • deadband: 0.5 so a quiet signal does not write every period
  • period: 10 000 ms
// Attach to the scheduler, and cancel
ins.scheduleDataTransfer("hourly_energy_calc");
ins.cancelDataTransfer("hourly_energy_calc");
// "Scheduled" or "Not Scheduled"
var status = ins.getDataTransferStatus("hourly_energy_calc");
// Every transfer of the calling project, keyed by name
var all = ins.getDataTransferStatusesByProject();

Scheduling requires the SCHEDULE_DATA_TRANSFER permission and is recorded as an operator action in the audit log.

Details: Data Transfer API →