Importing is how outside data becomes usable FEWS data. An import module reads an
external file, service, or database (hop ①), renames it
to your internal vocabulary (hop ②), and stores it as a
fully-identified time series (hop
③). This guide covers the config file that drives all of
that: timeSeriesImportRun.
Every import file has the same skeleton: a general block that says where the
data is and how to read it, followed by one or more timeSeriesSet blocks that
say what internal series to create.
timeSeriesImportRun
└─ import
├─ general ← the source + the reader + the mappings
general starts by choosing how to read the source. There are three mutually
exclusive ways — pick exactly one:
Element
Use when
Example value
importTypeStandard
The source is one of FEWS’s ~139 built-in formats.
BUFR, AsciiGrid, Aquarius…
importType
You’re using a general/named reader the import module supports but that isn’t in the standard enum (this is where the general tabular/CSV readers live).
folder is where FEWS looks for files; $IMPORT_FOLDER$ is a global
property (defined in global.properties) so the path isn’t hard-coded per
machine. fileNamePatternFilter narrows which files in that folder to read.
Timestamps in the file carry no time zone of their own — you must declare the
zone the data is in. Use <timeZoneName> (e.g. GMT) or an explicit
<timeZoneOffset> like +01:00. Getting this wrong shifts every value in time.
idMapId names the ID map that turns GAUGE-A /
discharge into RiverGauge_01 / Q.obs. Add unitConversionsId if the
source’s units differ from your parameter’s, and flagConversionsId if it
carries its own quality flags.
This uses internal ids — the names the ID map maps to. timeSeriesType
is external historical because this is observed data that arrived from
outside. The moduleInstanceId becomes part of the stored series’
header — remember it, because your
filter or display must ask for the data under the
same id. readWriteMode is required on every timeSeriesSet; add originals is the conventional value for imports (its semantics only matter to
the display — see Gotchas).
You rarely write one timeSeriesSet per gauge. Swap locationId for a
locationSetId and a single set imports the whole group — every location in the
set, mapped through the same ID map:
Different units in the source. Add unitConversionsId; FEWS converts to
your parameter’s unit on the way in. Same idea for quality flags via
flagConversionsId.
Missing-value markers. Sources often use -999 or NaN for gaps. List
them with missingValue (numeric) or missingValueText (string) so they’re
stored as missing, not as real readings.
Importing forecasts, not observations. Set timeSeriesType to
external forecasting. Everything else is the same pipeline — see the
lifecycle.
What happens to files after import. By default files are left in place;
use backupFolder / failedFolder to move processed and rejected files aside,
or deleteImportedFiles to remove them. This keeps the import folder from
growing without bound.
Turn mapping failures into hard errors while developing. See the gotchas
below — failOnUnmappableTimeSeries is your friend early on.
Nothing imports → the ID map didn’t match. Only series matching an
ID map entry are stored; the rest are dropped. A single
casing or punctuation difference (GAUGE_A vs GAUGE-A) is the most common
cause. While building, set failOnUnmappableTimeSeries to true so unmapped
data is a loud error instead of a silent skip.
Imports but doesn’t display → header mismatch. The
filter/displaytimeSeriesSet must reconstruct the
same header the import wrote — same moduleInstanceId, parameterId,
locationId, timeSeriesType, and timeStep. Line them up field by field.
readWriteMode is required, but inert on import. The schema requires a
readWriteMode on everytimeSeriesSet, so include it — add originals is
the conventional value for imports. Its read-only-vs-editable semantics,
though, only affect the Time Series Display; on import the value doesn’t change
how data is written, so don’t rely on it to.
Every value is time-shifted → wrong importTimeZone. The source timestamps
are interpreted in the zone you declare; declare the wrong one and the whole
series slides.
A change has no effect → a higher-versioned file wins. Check for a sibling
like ImportObservations 1.01 default.xml. See how FEWS finds a
file.
Run the import (via a workflow, as in the tutorial) and
read the log. Unmapped series show up as warnings here — or as errors if you
set failOnUnmappableTimeSeries.
Browse the data. Add a filter whose
timeSeriesSet matches the header you wrote, and confirm the series appears on
the chart with the values and timestamps you expect.
Sanity-check time and units. If the shape looks right but the timing or
magnitude is off, suspect importTimeZone or a missing unitConversionsId.