[{"data":1,"prerenderedAt":1301},["ShallowReactive",2],{"page-\u002Futils\u002Fguides\u002Flogger-import":3,"navigation":919},{"collection":4,"page":5},"docs_en",{"id":6,"title":7,"body":8,"description":911,"extension":912,"meta":913,"navigation":101,"path":914,"rawbody":915,"seo":916,"stem":917,"__hash__":918},"docs_en\u002Futils\u002F2.guides\u002F6.logger-import.md","Logger import",{"type":9,"value":10,"toc":904},"minimark",[11,35,41,46,386,436,440,667,683,687,690,787,800,804,811,868,878,882,900],[12,13,14,15,19,20,26,27,30,31,34],"p",{},"A pressure transducer left in a well records the water level every few minutes for months. Since 2.4, such a record is a ",[16,17,18],"code",{},"logger_series"," hydrodynamic event: a continuous series, not a pumping test and not a static level (",[21,22,24],"a",{"href":23},"\u002Fformat\u002Fspec\u002Fv2\u002Fobject-schemas#logger_series-since-v24",[16,25,18],{},"). Each reading has a ",[16,28,29],{},"datetime"," (an RFC 3339 instant) and a ",[16,32,33],{},"depth"," below ground.",[12,36,37,40],{},[16,38,39],{},"@welldot\u002Futils"," turns a logger's CSV export into those readings. There are no vendor-specific parsers: you map the columns once for your logger model.",[42,43,45],"h2",{"id":44},"from-csv-to-readings","From CSV to readings",[47,48,53],"pre",{"className":49,"code":50,"language":51,"meta":52,"style":52},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { buildLoggerReadings, parseDelimitedText } from '@welldot\u002Futils';\n\nconst text = `date;time;level\n01\u002F03\u002F2025;00:00;12.40\n01\u002F03\u002F2025;01:00;12.38\n01\u002F03\u002F2025;02:00;---`;\n\nconst { rows } = parseDelimitedText(text); \u002F\u002F detects , ; or tab, handles quotes\n\nconst { readings, skipped } = buildLoggerReadings(rows, {\n  headerRows: 1,\n  dateColumn: 0,\n  timeColumn: 1,\n  valueColumn: 2,\n  valueKind: 'water_column', \u002F\u002F the logger reports water above the sensor\n  sensorDepth: 42, \u002F\u002F so depth = 42 − value\n  dateFormat: 'dmy',\n  timeZone: 'America\u002FBelem', \u002F\u002F or offset: '-03:00'\n});\n\n\u002F\u002F readings: [\n\u002F\u002F   { datetime: '2025-03-01T00:00:00-03:00', depth: 29.6 },\n\u002F\u002F   { datetime: '2025-03-01T01:00:00-03:00', depth: 29.62 }\n\u002F\u002F ]\n\u002F\u002F skipped: [{ row: 3, issue: 'invalid_value' }]\n","ts","",[16,54,55,96,103,122,128,134,145,150,179,184,213,230,243,255,268,288,304,321,341,351,356,362,368,374,380],{"__ignoreMap":52},[56,57,60,64,68,72,75,78,81,84,87,90,93],"span",{"class":58,"line":59},"line",1,[56,61,63],{"class":62},"s7zQu","import",[56,65,67],{"class":66},"sMK4o"," {",[56,69,71],{"class":70},"sTEyZ"," buildLoggerReadings",[56,73,74],{"class":66},",",[56,76,77],{"class":70}," parseDelimitedText",[56,79,80],{"class":66}," }",[56,82,83],{"class":62}," from",[56,85,86],{"class":66}," '",[56,88,39],{"class":89},"sfazB",[56,91,92],{"class":66},"'",[56,94,95],{"class":66},";\n",[56,97,99],{"class":58,"line":98},2,[56,100,102],{"emptyLinePlaceholder":101},true,"\n",[56,104,106,110,113,116,119],{"class":58,"line":105},3,[56,107,109],{"class":108},"spNyl","const",[56,111,112],{"class":70}," text ",[56,114,115],{"class":66},"=",[56,117,118],{"class":66}," `",[56,120,121],{"class":89},"date;time;level\n",[56,123,125],{"class":58,"line":124},4,[56,126,127],{"class":89},"01\u002F03\u002F2025;00:00;12.40\n",[56,129,131],{"class":58,"line":130},5,[56,132,133],{"class":89},"01\u002F03\u002F2025;01:00;12.38\n",[56,135,137,140,143],{"class":58,"line":136},6,[56,138,139],{"class":89},"01\u002F03\u002F2025;02:00;---",[56,141,142],{"class":66},"`",[56,144,95],{"class":66},[56,146,148],{"class":58,"line":147},7,[56,149,102],{"emptyLinePlaceholder":101},[56,151,153,155,157,160,163,166,169,172,175],{"class":58,"line":152},8,[56,154,109],{"class":108},[56,156,67],{"class":66},[56,158,159],{"class":70}," rows ",[56,161,162],{"class":66},"}",[56,164,165],{"class":66}," =",[56,167,77],{"class":168},"s2Zo4",[56,170,171],{"class":70},"(text)",[56,173,174],{"class":66},";",[56,176,178],{"class":177},"sHwdD"," \u002F\u002F detects , ; or tab, handles quotes\n",[56,180,182],{"class":58,"line":181},9,[56,183,102],{"emptyLinePlaceholder":101},[56,185,187,189,191,194,196,199,201,203,205,208,210],{"class":58,"line":186},10,[56,188,109],{"class":108},[56,190,67],{"class":66},[56,192,193],{"class":70}," readings",[56,195,74],{"class":66},[56,197,198],{"class":70}," skipped ",[56,200,162],{"class":66},[56,202,165],{"class":66},[56,204,71],{"class":168},[56,206,207],{"class":70},"(rows",[56,209,74],{"class":66},[56,211,212],{"class":66}," {\n",[56,214,216,220,223,227],{"class":58,"line":215},11,[56,217,219],{"class":218},"swJcz","  headerRows",[56,221,222],{"class":66},":",[56,224,226],{"class":225},"sbssI"," 1",[56,228,229],{"class":66},",\n",[56,231,233,236,238,241],{"class":58,"line":232},12,[56,234,235],{"class":218},"  dateColumn",[56,237,222],{"class":66},[56,239,240],{"class":225}," 0",[56,242,229],{"class":66},[56,244,246,249,251,253],{"class":58,"line":245},13,[56,247,248],{"class":218},"  timeColumn",[56,250,222],{"class":66},[56,252,226],{"class":225},[56,254,229],{"class":66},[56,256,258,261,263,266],{"class":58,"line":257},14,[56,259,260],{"class":218},"  valueColumn",[56,262,222],{"class":66},[56,264,265],{"class":225}," 2",[56,267,229],{"class":66},[56,269,271,274,276,278,281,283,285],{"class":58,"line":270},15,[56,272,273],{"class":218},"  valueKind",[56,275,222],{"class":66},[56,277,86],{"class":66},[56,279,280],{"class":89},"water_column",[56,282,92],{"class":66},[56,284,74],{"class":66},[56,286,287],{"class":177}," \u002F\u002F the logger reports water above the sensor\n",[56,289,291,294,296,299,301],{"class":58,"line":290},16,[56,292,293],{"class":218},"  sensorDepth",[56,295,222],{"class":66},[56,297,298],{"class":225}," 42",[56,300,74],{"class":66},[56,302,303],{"class":177}," \u002F\u002F so depth = 42 − value\n",[56,305,307,310,312,314,317,319],{"class":58,"line":306},17,[56,308,309],{"class":218},"  dateFormat",[56,311,222],{"class":66},[56,313,86],{"class":66},[56,315,316],{"class":89},"dmy",[56,318,92],{"class":66},[56,320,229],{"class":66},[56,322,324,327,329,331,334,336,338],{"class":58,"line":323},18,[56,325,326],{"class":218},"  timeZone",[56,328,222],{"class":66},[56,330,86],{"class":66},[56,332,333],{"class":89},"America\u002FBelem",[56,335,92],{"class":66},[56,337,74],{"class":66},[56,339,340],{"class":177}," \u002F\u002F or offset: '-03:00'\n",[56,342,344,346,349],{"class":58,"line":343},19,[56,345,162],{"class":66},[56,347,348],{"class":70},")",[56,350,95],{"class":66},[56,352,354],{"class":58,"line":353},20,[56,355,102],{"emptyLinePlaceholder":101},[56,357,359],{"class":58,"line":358},21,[56,360,361],{"class":177},"\u002F\u002F readings: [\n",[56,363,365],{"class":58,"line":364},22,[56,366,367],{"class":177},"\u002F\u002F   { datetime: '2025-03-01T00:00:00-03:00', depth: 29.6 },\n",[56,369,371],{"class":58,"line":370},23,[56,372,373],{"class":177},"\u002F\u002F   { datetime: '2025-03-01T01:00:00-03:00', depth: 29.62 }\n",[56,375,377],{"class":58,"line":376},24,[56,378,379],{"class":177},"\u002F\u002F ]\n",[56,381,383],{"class":58,"line":382},25,[56,384,385],{"class":177},"\u002F\u002F skipped: [{ row: 3, issue: 'invalid_value' }]\n",[387,388,389,404,415],"ul",{},[390,391,392,395,396,399,400,403],"li",{},[16,393,394],{},"valueKind: 'depth'"," takes the value as the depth to water; ",[16,397,398],{},"'water_column'"," converts the height of water above the sensor using ",[16,401,402],{},"sensorDepth",".",[390,405,406,407,410,411,414],{},"Times are local to the logger. Give the IANA ",[16,408,409],{},"timeZone"," of the site, and each reading gets the offset in force at that moment, daylight saving included. A fixed ",[16,412,413],{},"offset"," also works.",[390,416,417,418,421,422,425,426,425,429,425,432,435],{},"Rows that cannot be read are listed in ",[16,419,420],{},"skipped"," with a reason (",[16,423,424],{},"invalid_date",", ",[16,427,428],{},"invalid_value",[16,430,431],{},"missing_sensor_depth",[16,433,434],{},"missing_offset","), never silently dropped.",[42,437,439],{"id":438},"into-the-file","Into the file",[47,441,443],{"className":49,"code":442,"language":51,"meta":52,"style":52},"import { inferLoggerInterval } from '@welldot\u002Futils';\n\nwell.hydrodynamic_events = [\n  ...(well.hydrodynamic_events ?? []),\n  {\n    id: crypto.randomUUID(),\n    type: 'logger_series',\n    datetime: readings[0].datetime,\n    measurement_method: 'pressure_transducer',\n    sensor_depth: 42,\n    interval: inferLoggerInterval(readings), \u002F\u002F 60 (minutes)\n    barometric_compensation: 'barologger', \u002F\u002F closed: barologger, vented or none\n    aggregation: 'none', \u002F\u002F closed: none, hourly or daily\n    readings,\n  },\n];\n",[16,444,445,466,470,485,505,510,530,545,567,583,594,611,630,649,656,661],{"__ignoreMap":52},[56,446,447,449,451,454,456,458,460,462,464],{"class":58,"line":59},[56,448,63],{"class":62},[56,450,67],{"class":66},[56,452,453],{"class":70}," inferLoggerInterval",[56,455,80],{"class":66},[56,457,83],{"class":62},[56,459,86],{"class":66},[56,461,39],{"class":89},[56,463,92],{"class":66},[56,465,95],{"class":66},[56,467,468],{"class":58,"line":98},[56,469,102],{"emptyLinePlaceholder":101},[56,471,472,475,477,480,482],{"class":58,"line":105},[56,473,474],{"class":70},"well",[56,476,403],{"class":66},[56,478,479],{"class":70},"hydrodynamic_events ",[56,481,115],{"class":66},[56,483,484],{"class":70}," [\n",[56,486,487,490,493,495,497,500,503],{"class":58,"line":124},[56,488,489],{"class":66},"  ...",[56,491,492],{"class":70},"(well",[56,494,403],{"class":66},[56,496,479],{"class":70},[56,498,499],{"class":66},"??",[56,501,502],{"class":70}," [])",[56,504,229],{"class":66},[56,506,507],{"class":58,"line":130},[56,508,509],{"class":66},"  {\n",[56,511,512,515,517,520,522,525,528],{"class":58,"line":136},[56,513,514],{"class":218},"    id",[56,516,222],{"class":66},[56,518,519],{"class":70}," crypto",[56,521,403],{"class":66},[56,523,524],{"class":168},"randomUUID",[56,526,527],{"class":70},"()",[56,529,229],{"class":66},[56,531,532,535,537,539,541,543],{"class":58,"line":147},[56,533,534],{"class":218},"    type",[56,536,222],{"class":66},[56,538,86],{"class":66},[56,540,18],{"class":89},[56,542,92],{"class":66},[56,544,229],{"class":66},[56,546,547,550,552,555,558,561,563,565],{"class":58,"line":152},[56,548,549],{"class":218},"    datetime",[56,551,222],{"class":66},[56,553,554],{"class":70}," readings[",[56,556,557],{"class":225},"0",[56,559,560],{"class":70},"]",[56,562,403],{"class":66},[56,564,29],{"class":70},[56,566,229],{"class":66},[56,568,569,572,574,576,579,581],{"class":58,"line":181},[56,570,571],{"class":218},"    measurement_method",[56,573,222],{"class":66},[56,575,86],{"class":66},[56,577,578],{"class":89},"pressure_transducer",[56,580,92],{"class":66},[56,582,229],{"class":66},[56,584,585,588,590,592],{"class":58,"line":186},[56,586,587],{"class":218},"    sensor_depth",[56,589,222],{"class":66},[56,591,298],{"class":225},[56,593,229],{"class":66},[56,595,596,599,601,603,606,608],{"class":58,"line":215},[56,597,598],{"class":218},"    interval",[56,600,222],{"class":66},[56,602,453],{"class":168},[56,604,605],{"class":70},"(readings)",[56,607,74],{"class":66},[56,609,610],{"class":177}," \u002F\u002F 60 (minutes)\n",[56,612,613,616,618,620,623,625,627],{"class":58,"line":232},[56,614,615],{"class":218},"    barometric_compensation",[56,617,222],{"class":66},[56,619,86],{"class":66},[56,621,622],{"class":89},"barologger",[56,624,92],{"class":66},[56,626,74],{"class":66},[56,628,629],{"class":177}," \u002F\u002F closed: barologger, vented or none\n",[56,631,632,635,637,639,642,644,646],{"class":58,"line":245},[56,633,634],{"class":218},"    aggregation",[56,636,222],{"class":66},[56,638,86],{"class":66},[56,640,641],{"class":89},"none",[56,643,92],{"class":66},[56,645,74],{"class":66},[56,647,648],{"class":177}," \u002F\u002F closed: none, hourly or daily\n",[56,650,651,654],{"class":58,"line":257},[56,652,653],{"class":70},"    readings",[56,655,229],{"class":66},[56,657,658],{"class":58,"line":270},[56,659,660],{"class":66},"  },\n",[56,662,663,665],{"class":58,"line":290},[56,664,560],{"class":70},[56,666,95],{"class":66},[12,668,669,670,673,674,677,678,682],{},"Check the spec for the meaning of each field; hourly or daily aggregation requires ",[16,671,672],{},"depth_min"," and ",[16,675,676],{},"depth_max"," on every reading (",[21,679,680],{"href":23},[16,681,18],{},").",[42,684,686],{"id":685},"adding-a-new-download","Adding a new download",[12,688,689],{},"Loggers are downloaded again and again, and the exports overlap:",[47,691,693],{"className":49,"code":692,"language":51,"meta":52,"style":52},"import { mergeLoggerReadings } from '@welldot\u002Futils';\n\nconst { readings: merged, replaced } = mergeLoggerReadings(\n  event.readings,\n  newReadings,\n  'append', \u002F\u002F or 'replace'\n);\n",[16,694,695,716,720,747,759,766,781],{"__ignoreMap":52},[56,696,697,699,701,704,706,708,710,712,714],{"class":58,"line":59},[56,698,63],{"class":62},[56,700,67],{"class":66},[56,702,703],{"class":70}," mergeLoggerReadings",[56,705,80],{"class":66},[56,707,83],{"class":62},[56,709,86],{"class":66},[56,711,39],{"class":89},[56,713,92],{"class":66},[56,715,95],{"class":66},[56,717,718],{"class":58,"line":98},[56,719,102],{"emptyLinePlaceholder":101},[56,721,722,724,726,728,730,733,735,738,740,742,744],{"class":58,"line":105},[56,723,109],{"class":108},[56,725,67],{"class":66},[56,727,193],{"class":218},[56,729,222],{"class":66},[56,731,732],{"class":70}," merged",[56,734,74],{"class":66},[56,736,737],{"class":70}," replaced ",[56,739,162],{"class":66},[56,741,165],{"class":66},[56,743,703],{"class":168},[56,745,746],{"class":70},"(\n",[56,748,749,752,754,757],{"class":58,"line":124},[56,750,751],{"class":70},"  event",[56,753,403],{"class":66},[56,755,756],{"class":70},"readings",[56,758,229],{"class":66},[56,760,761,764],{"class":58,"line":130},[56,762,763],{"class":70},"  newReadings",[56,765,229],{"class":66},[56,767,768,771,774,776,778],{"class":58,"line":136},[56,769,770],{"class":66},"  '",[56,772,773],{"class":89},"append",[56,775,92],{"class":66},[56,777,74],{"class":66},[56,779,780],{"class":177}," \u002F\u002F or 'replace'\n",[56,782,783,785],{"class":58,"line":147},[56,784,348],{"class":70},[56,786,95],{"class":66},[12,788,789,790,793,794,796,797,682],{},"Readings are merged by instant, the incoming value wins on a tie, and the result is sorted. ",[16,791,792],{},"replaced"," counts the readings that were overwritten (",[16,795,773],{},") or dropped (",[16,798,799],{},"replace",[42,801,803],{"id":802},"plotting","Plotting",[12,805,806,807,810],{},"A year of 15-minute readings is 35,000 points. ",[16,808,809],{},"downsampleLoggerReadings(readings, maxPoints)"," keeps the first and last readings and the minimum and maximum depth of each bucket, so peaks survive:",[47,812,814],{"className":49,"code":813,"language":51,"meta":52,"style":52},"import { downsampleLoggerReadings } from '@welldot\u002Futils';\n\nconst plotted = downsampleLoggerReadings(event.readings, 2000);\n",[16,815,816,837,841],{"__ignoreMap":52},[56,817,818,820,822,825,827,829,831,833,835],{"class":58,"line":59},[56,819,63],{"class":62},[56,821,67],{"class":66},[56,823,824],{"class":70}," downsampleLoggerReadings",[56,826,80],{"class":66},[56,828,83],{"class":62},[56,830,86],{"class":66},[56,832,39],{"class":89},[56,834,92],{"class":66},[56,836,95],{"class":66},[56,838,839],{"class":58,"line":98},[56,840,102],{"emptyLinePlaceholder":101},[56,842,843,845,848,850,852,855,857,859,861,864,866],{"class":58,"line":105},[56,844,109],{"class":108},[56,846,847],{"class":70}," plotted ",[56,849,115],{"class":66},[56,851,824],{"class":168},[56,853,854],{"class":70},"(event",[56,856,403],{"class":66},[56,858,756],{"class":70},[56,860,74],{"class":66},[56,862,863],{"class":225}," 2000",[56,865,348],{"class":70},[56,867,95],{"class":66},[12,869,870,873,874,877],{},[16,871,872],{},"localDateTimeToInstant('2025-03-01T00:00', 'America\u002FBelem')"," converts one local time to an instant (",[16,875,876],{},"'2025-03-01T00:00:00-03:00'",") if you parse files yourself.",[42,879,881],{"id":880},"warnings","Warnings",[12,883,884,887,888,891,892,895,896,682],{},[16,885,886],{},"getOperationWarnings"," reports ",[16,889,890],{},"logger_reading_below_sensor"," (a reading deeper than the sensor) and ",[16,893,894],{},"analysis_uses_logger_series"," (an aquifer analysis citing a logger series, which is not a controlled test) (",[21,897,899],{"href":898},"\u002Futils\u002Fguides\u002Foperation","Operation and production",[901,902,903],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":52,"searchDepth":98,"depth":98,"links":905},[906,907,908,909,910],{"id":44,"depth":98,"text":45},{"id":438,"depth":98,"text":439},{"id":685,"depth":98,"text":686},{"id":802,"depth":98,"text":803},{"id":880,"depth":98,"text":881},"Turn a pressure transducer or data logger export into logger_series readings, with column mapping, time zones, merging and downsampling, using @welldot\u002Futils.","md",{},"\u002Futils\u002Fguides\u002Flogger-import","---\ntitle: Logger import\ndescription: Turn a pressure transducer or data logger export into logger_series readings, with column mapping, time zones, merging and downsampling, using @welldot\u002Futils.\n---\n\nA pressure transducer left in a well records the water level every few minutes for months. Since 2.4, such a record is a `logger_series` hydrodynamic event: a continuous series, not a pumping test and not a static level ([`logger_series`](\u002Fformat\u002Fspec\u002Fv2\u002Fobject-schemas#logger_series-since-v24)). Each reading has a `datetime` (an RFC 3339 instant) and a `depth` below ground.\n\n`@welldot\u002Futils` turns a logger's CSV export into those readings. There are no vendor-specific parsers: you map the columns once for your logger model.\n\n## From CSV to readings\n\n```ts\nimport { buildLoggerReadings, parseDelimitedText } from '@welldot\u002Futils';\n\nconst text = `date;time;level\n01\u002F03\u002F2025;00:00;12.40\n01\u002F03\u002F2025;01:00;12.38\n01\u002F03\u002F2025;02:00;---`;\n\nconst { rows } = parseDelimitedText(text); \u002F\u002F detects , ; or tab, handles quotes\n\nconst { readings, skipped } = buildLoggerReadings(rows, {\n  headerRows: 1,\n  dateColumn: 0,\n  timeColumn: 1,\n  valueColumn: 2,\n  valueKind: 'water_column', \u002F\u002F the logger reports water above the sensor\n  sensorDepth: 42, \u002F\u002F so depth = 42 − value\n  dateFormat: 'dmy',\n  timeZone: 'America\u002FBelem', \u002F\u002F or offset: '-03:00'\n});\n\n\u002F\u002F readings: [\n\u002F\u002F   { datetime: '2025-03-01T00:00:00-03:00', depth: 29.6 },\n\u002F\u002F   { datetime: '2025-03-01T01:00:00-03:00', depth: 29.62 }\n\u002F\u002F ]\n\u002F\u002F skipped: [{ row: 3, issue: 'invalid_value' }]\n```\n\n- `valueKind: 'depth'` takes the value as the depth to water; `'water_column'` converts the height of water above the sensor using `sensorDepth`.\n- Times are local to the logger. Give the IANA `timeZone` of the site, and each reading gets the offset in force at that moment, daylight saving included. A fixed `offset` also works.\n- Rows that cannot be read are listed in `skipped` with a reason (`invalid_date`, `invalid_value`, `missing_sensor_depth`, `missing_offset`), never silently dropped.\n\n## Into the file\n\n```ts\nimport { inferLoggerInterval } from '@welldot\u002Futils';\n\nwell.hydrodynamic_events = [\n  ...(well.hydrodynamic_events ?? []),\n  {\n    id: crypto.randomUUID(),\n    type: 'logger_series',\n    datetime: readings[0].datetime,\n    measurement_method: 'pressure_transducer',\n    sensor_depth: 42,\n    interval: inferLoggerInterval(readings), \u002F\u002F 60 (minutes)\n    barometric_compensation: 'barologger', \u002F\u002F closed: barologger, vented or none\n    aggregation: 'none', \u002F\u002F closed: none, hourly or daily\n    readings,\n  },\n];\n```\n\nCheck the spec for the meaning of each field; hourly or daily aggregation requires `depth_min` and `depth_max` on every reading ([`logger_series`](\u002Fformat\u002Fspec\u002Fv2\u002Fobject-schemas#logger_series-since-v24)).\n\n## Adding a new download\n\nLoggers are downloaded again and again, and the exports overlap:\n\n```ts\nimport { mergeLoggerReadings } from '@welldot\u002Futils';\n\nconst { readings: merged, replaced } = mergeLoggerReadings(\n  event.readings,\n  newReadings,\n  'append', \u002F\u002F or 'replace'\n);\n```\n\nReadings are merged by instant, the incoming value wins on a tie, and the result is sorted. `replaced` counts the readings that were overwritten (`append`) or dropped (`replace`).\n\n## Plotting\n\nA year of 15-minute readings is 35,000 points. `downsampleLoggerReadings(readings, maxPoints)` keeps the first and last readings and the minimum and maximum depth of each bucket, so peaks survive:\n\n```ts\nimport { downsampleLoggerReadings } from '@welldot\u002Futils';\n\nconst plotted = downsampleLoggerReadings(event.readings, 2000);\n```\n\n`localDateTimeToInstant('2025-03-01T00:00', 'America\u002FBelem')` converts one local time to an instant (`'2025-03-01T00:00:00-03:00'`) if you parse files yourself.\n\n## Warnings\n\n`getOperationWarnings` reports `logger_reading_below_sensor` (a reading deeper than the sensor) and `analysis_uses_logger_series` (an aquifer analysis citing a logger series, which is not a controlled test) ([Operation and production](\u002Futils\u002Fguides\u002Foperation)).\n",{"title":7,"description":911},"utils\u002F2.guides\u002F6.logger-import","Jqoki9uZ_EmkeeEHhkvVSwtEjGavGavenZRdFvCPR3s",{"docs_en":920,"spec":1233,"changelogs":1283},[921,941,960,1016,1126,1180],{"title":922,"path":923,"stem":924,"children":925},"Ai","\u002Fai","ai",[926,929,933,937],{"title":927,"path":923,"stem":928},"Introduction","ai\u002Findex",{"title":930,"path":931,"stem":932},"Converting reports with an assistant","\u002Fai\u002Fconversion-skill","ai\u002Fconversion-skill",{"title":934,"path":935,"stem":936},"llms.txt and Markdown pages","\u002Fai\u002Fllms","ai\u002Fllms",{"title":938,"path":939,"stem":940},"MCP server","\u002Fai\u002Fmcp","ai\u002Fmcp",{"title":942,"path":943,"stem":944,"children":945},"Contributing","\u002Fcontributing","contributing",[946,948,952,956],{"title":927,"path":943,"stem":947},"contributing\u002Findex",{"title":949,"path":950,"stem":951},"Writing docs","\u002Fcontributing\u002Fwriting-docs","contributing\u002F1.writing-docs",{"title":953,"path":954,"stem":955},"Update rules","\u002Fcontributing\u002Fupdate-rules","contributing\u002F2.update-rules",{"title":957,"path":958,"stem":959},"Content components","\u002Fcontributing\u002Fcomponents","contributing\u002Fcomponents",{"title":961,"path":962,"stem":963,"children":964},"Core","\u002Fcore","core",[965,967,981,1010],{"title":927,"path":962,"stem":966},"core\u002Findex",{"title":968,"path":969,"stem":970,"children":971,"page":980},"Getting Started","\u002Fcore\u002Fgetting-started","core\u002F1.getting-started",[972,976],{"title":973,"path":974,"stem":975},"Installation","\u002Fcore\u002Fgetting-started\u002Finstallation","core\u002F1.getting-started\u002F1.installation",{"title":977,"path":978,"stem":979},"First use","\u002Fcore\u002Fgetting-started\u002Ffirst-use","core\u002F1.getting-started\u002F2.first-use",false,{"title":982,"path":983,"stem":984,"children":985,"page":980},"Guides","\u002Fcore\u002Fguides","core\u002F2.guides",[986,990,994,998,1002,1006],{"title":987,"path":988,"stem":989},"Parsing and validating","\u002Fcore\u002Fguides\u002Fparsing-and-validating","core\u002F2.guides\u002F1.parsing-and-validating",{"title":991,"path":992,"stem":993},"Serializing and sharing","\u002Fcore\u002Fguides\u002Fserializing-and-sharing","core\u002F2.guides\u002F2.serializing-and-sharing",{"title":995,"path":996,"stem":997},"Unit conversion","\u002Fcore\u002Fguides\u002Funit-conversion","core\u002F2.guides\u002F3.unit-conversion",{"title":999,"path":1000,"stem":1001},"Vocabularies and textures","\u002Fcore\u002Fguides\u002Fvocabularies-and-textures","core\u002F2.guides\u002F4.vocabularies-and-textures",{"title":1003,"path":1004,"stem":1005},"Water quality vocabulary","\u002Fcore\u002Fguides\u002Fwater-quality-vocabulary","core\u002F2.guides\u002F5.water-quality-vocabulary",{"title":1007,"path":1008,"stem":1009},"Versions and time zones","\u002Fcore\u002Fguides\u002Fversions-and-time-zones","core\u002F2.guides\u002F6.versions-and-time-zones",{"title":1011,"path":1012,"stem":1013,"children":1014},"API reference","\u002Fcore\u002Fapi","core\u002Fapi\u002Findex",[1015],{"title":1011,"path":1012,"stem":1013},{"title":1017,"path":1018,"stem":1019,"children":1020},"Format","\u002Fformat","format",[1021,1023,1043,1072,1096,1116,1122],{"title":927,"path":1018,"stem":1022},"format\u002Findex",{"title":968,"path":1024,"stem":1025,"children":1026,"page":980},"\u002Fformat\u002Fgetting-started","format\u002F1.getting-started",[1027,1031,1035,1039],{"title":1028,"path":1029,"stem":1030},"What is .well?","\u002Fformat\u002Fgetting-started\u002Fwhat-is-well","format\u002F1.getting-started\u002F1.what-is-well",{"title":1032,"path":1033,"stem":1034},"For geologists","\u002Fformat\u002Fgetting-started\u002Ffor-geologists","format\u002F1.getting-started\u002F2.for-geologists",{"title":1036,"path":1037,"stem":1038},"For developers","\u002Fformat\u002Fgetting-started\u002Ffor-developers","format\u002F1.getting-started\u002F3.for-developers",{"title":1040,"path":1041,"stem":1042},"Your first .well file","\u002Fformat\u002Fgetting-started\u002Ffirst-well-file","format\u002F1.getting-started\u002F4.first-well-file",{"title":1044,"path":1045,"stem":1046,"children":1047,"page":980},"Concepts","\u002Fformat\u002Fconcepts","format\u002F2.concepts",[1048,1052,1056,1060,1064,1068],{"title":1049,"path":1050,"stem":1051},"Depths and intervals","\u002Fformat\u002Fconcepts\u002Fdepths-and-intervals","format\u002F2.concepts\u002F1.depths-and-intervals",{"title":1053,"path":1054,"stem":1055},"Units and precision","\u002Fformat\u002Fconcepts\u002Funits-and-precision","format\u002F2.concepts\u002F2.units-and-precision",{"title":1057,"path":1058,"stem":1059},"Vocabularies","\u002Fformat\u002Fconcepts\u002Fvocabularies","format\u002F2.concepts\u002F3.vocabularies",{"title":1061,"path":1062,"stem":1063},"Profiles","\u002Fformat\u002Fconcepts\u002Fprofiles","format\u002F2.concepts\u002F4.profiles",{"title":1065,"path":1066,"stem":1067},"Versions and deprecation","\u002Fformat\u002Fconcepts\u002Fversions-and-deprecation","format\u002F2.concepts\u002F5.versions-and-deprecation",{"title":1069,"path":1070,"stem":1071},"Extensibility","\u002Fformat\u002Fconcepts\u002Fextensibility","format\u002F2.concepts\u002F6.extensibility",{"title":982,"path":1073,"stem":1074,"children":1075,"page":980},"\u002Fformat\u002Fguides","format\u002F3.guides",[1076,1080,1084,1088,1092],{"title":1077,"path":1078,"stem":1079},"Writing a .well by hand","\u002Fformat\u002Fguides\u002Fwriting-by-hand","format\u002F3.guides\u002F1.writing-by-hand",{"title":1081,"path":1082,"stem":1083},"Converting a report","\u002Fformat\u002Fguides\u002Fconverting-a-report","format\u002F3.guides\u002F2.converting-a-report",{"title":1085,"path":1086,"stem":1087},"Validating","\u002Fformat\u002Fguides\u002Fvalidating","format\u002F3.guides\u002F3.validating",{"title":1089,"path":1090,"stem":1091},"Extending for your own needs","\u002Fformat\u002Fguides\u002Fextending","format\u002F3.guides\u002F4.extending",{"title":1093,"path":1094,"stem":1095},"Building an editor or database on .well","\u002Fformat\u002Fguides\u002Fbuilding-on-well","format\u002F3.guides\u002F5.building-on-well",{"title":1097,"path":1098,"stem":1099,"children":1100},"Overview","\u002Fformat\u002Freference","format\u002F4.reference\u002Findex",[1101,1102,1106,1110],{"title":1097,"path":1098,"stem":1099},{"title":1103,"path":1104,"stem":1105},"JSON Schema","\u002Fformat\u002Freference\u002Fjson-schema","format\u002F4.reference\u002F1.json-schema",{"title":1107,"path":1108,"stem":1109},"Example wells","\u002Fformat\u002Freference\u002Fexamples","format\u002F4.reference\u002F2.examples",{"title":1111,"path":1112,"stem":1113,"children":1114},"Object reference","\u002Fformat\u002Freference\u002Fobjects","format\u002Freference\u002Fobjects\u002Findex",[1115],{"title":1111,"path":1112,"stem":1113},{"title":1117,"path":1118,"stem":1119,"children":1120},"About the spec","\u002Fformat\u002Fspec","format\u002F5.spec\u002Findex",[1121],{"title":1117,"path":1118,"stem":1119},{"title":1123,"path":1124,"stem":1125},"Changelog","\u002Fformat\u002Fchangelog","format\u002F6.changelog",{"title":1127,"path":1128,"stem":1129,"children":1130},"Render","\u002Frender","render",[1131,1133,1143,1175],{"title":927,"path":1128,"stem":1132},"render\u002Findex",{"title":968,"path":1134,"stem":1135,"children":1136,"page":980},"\u002Frender\u002Fgetting-started","render\u002F1.getting-started",[1137,1140],{"title":973,"path":1138,"stem":1139},"\u002Frender\u002Fgetting-started\u002Finstallation","render\u002F1.getting-started\u002F1.installation",{"title":977,"path":1141,"stem":1142},"\u002Frender\u002Fgetting-started\u002Ffirst-use","render\u002F1.getting-started\u002F2.first-use",{"title":982,"path":1144,"stem":1145,"children":1146,"page":980},"\u002Frender\u002Fguides","render\u002F2.guides",[1147,1151,1155,1159,1163,1167,1171],{"title":1148,"path":1149,"stem":1150},"Panels and layout","\u002Frender\u002Fguides\u002Fpanels-and-layout","render\u002F2.guides\u002F1.panels-and-layout",{"title":1152,"path":1153,"stem":1154},"Layers and labels","\u002Frender\u002Fguides\u002Flayers-and-labels","render\u002F2.guides\u002F2.layers-and-labels",{"title":1156,"path":1157,"stem":1158},"Theming","\u002Frender\u002Fguides\u002Ftheming","render\u002F2.guides\u002F3.theming",{"title":1160,"path":1161,"stem":1162},"Locale and units","\u002Frender\u002Fguides\u002Flocale-and-units","render\u002F2.guides\u002F4.locale-and-units",{"title":1164,"path":1165,"stem":1166},"Legends","\u002Frender\u002Fguides\u002Flegends","render\u002F2.guides\u002F5.legends",{"title":1168,"path":1169,"stem":1170},"Zoom, pan and highlights","\u002Frender\u002Fguides\u002Finteraction","render\u002F2.guides\u002F6.interaction",{"title":1172,"path":1173,"stem":1174},"Using it in a framework","\u002Frender\u002Fguides\u002Fframeworks","render\u002F2.guides\u002F7.frameworks",{"title":1011,"path":1176,"stem":1177,"children":1178},"\u002Frender\u002Fapi","render\u002Fapi\u002Findex",[1179],{"title":1011,"path":1176,"stem":1177},{"title":1181,"path":1182,"stem":1183,"children":1184},"Utils","\u002Futils","utils",[1185,1187,1197,1228],{"title":927,"path":1182,"stem":1186},"utils\u002Findex",{"title":968,"path":1188,"stem":1189,"children":1190,"page":980},"\u002Futils\u002Fgetting-started","utils\u002F1.getting-started",[1191,1194],{"title":973,"path":1192,"stem":1193},"\u002Futils\u002Fgetting-started\u002Finstallation","utils\u002F1.getting-started\u002F1.installation",{"title":977,"path":1195,"stem":1196},"\u002Futils\u002Fgetting-started\u002Ffirst-use","utils\u002F1.getting-started\u002F2.first-use",{"title":982,"path":1198,"stem":1199,"children":1200,"page":980},"\u002Futils\u002Fguides","utils\u002F2.guides",[1201,1205,1209,1213,1215,1219,1220,1224],{"title":1202,"path":1203,"stem":1204},"Geometry and volumes","\u002Futils\u002Fguides\u002Fgeometry-and-volumes","utils\u002F2.guides\u002F1.geometry-and-volumes",{"title":1206,"path":1207,"stem":1208},"Water levels and pumping tests","\u002Futils\u002Fguides\u002Fpumping-tests","utils\u002F2.guides\u002F2.pumping-tests",{"title":1210,"path":1211,"stem":1212},"Permits","\u002Futils\u002Fguides\u002Fpermits","utils\u002F2.guides\u002F3.permits",{"title":899,"path":898,"stem":1214},"utils\u002F2.guides\u002F4.operation",{"title":1216,"path":1217,"stem":1218},"Water quality","\u002Futils\u002Fguides\u002Fwater-quality","utils\u002F2.guides\u002F5.water-quality",{"title":7,"path":914,"stem":917},{"title":1221,"path":1222,"stem":1223},"SIAGAS import","\u002Futils\u002Fguides\u002Fsiagas-import","utils\u002F2.guides\u002F7.siagas-import",{"title":1225,"path":1226,"stem":1227},"Formatting","\u002Futils\u002Fguides\u002Fformatting","utils\u002F2.guides\u002F8.formatting",{"title":1011,"path":1229,"stem":1230,"children":1231},"\u002Futils\u002Fapi","utils\u002Fapi\u002Findex",[1232],{"title":1011,"path":1229,"stem":1230},[1234],{"title":1017,"path":1018,"stem":1019,"children":1235,"page":980},[1236],{"title":1237,"path":1118,"stem":1238,"children":1239,"page":980},"Spec","format\u002Fspec",[1240,1249,1258],{"title":1241,"path":1242,"stem":1243,"children":1244,"page":980},"Reference","\u002Fformat\u002Fspec\u002Freference","format\u002Fspec\u002Freference",[1245],{"title":1246,"path":1247,"stem":1248},"FGDC Texture Patterns Reference","\u002Fformat\u002Fspec\u002Freference\u002Ffgdc-textures","format\u002Fspec\u002Freference\u002Ffgdc-textures",{"title":1250,"path":1251,"stem":1252,"children":1253,"page":980},"V1","\u002Fformat\u002Fspec\u002Fv1","format\u002Fspec\u002Fv1",[1254],{"title":1255,"path":1256,"stem":1257},".well File Format Specification","\u002Fformat\u002Fspec\u002Fv1\u002Fwell-format","format\u002Fspec\u002Fv1\u002Fwell-format",{"title":1259,"path":1260,"stem":1261,"children":1262,"page":980},"V2","\u002Fformat\u002Fspec\u002Fv2","format\u002Fspec\u002Fv2",[1263,1267,1271,1275,1279],{"title":1264,"path":1265,"stem":1266},".well File Format Specification — Version 2.4: Format Reference","\u002Fformat\u002Fspec\u002Fv2\u002Fformat-reference","format\u002Fspec\u002Fv2\u002Fformat-reference",{"title":1268,"path":1269,"stem":1270},".well File Format Specification — Version 2.4: Interoperability","\u002Fformat\u002Fspec\u002Fv2\u002Finteroperability","format\u002Fspec\u002Fv2\u002Finteroperability",{"title":1272,"path":1273,"stem":1274},".well File Format Specification — Version 2.4: Object Schemas","\u002Fformat\u002Fspec\u002Fv2\u002Fobject-schemas","format\u002Fspec\u002Fv2\u002Fobject-schemas",{"title":1276,"path":1277,"stem":1278},".well File Format Specification — Version 2.4: Overview","\u002Fformat\u002Fspec\u002Fv2\u002Foverview","format\u002Fspec\u002Fv2\u002Foverview",{"title":1280,"path":1281,"stem":1282},".well File Format Specification — Version 2.4: Water Quality","\u002Fformat\u002Fspec\u002Fv2\u002Fwater-quality","format\u002Fspec\u002Fv2\u002Fwater-quality",[1284,1290,1296],{"title":961,"path":962,"stem":963,"children":1285,"page":980},[1286],{"title":1287,"path":1288,"stem":1289},"@welldot\u002Fcore","\u002Fcore\u002Fchangelog","core\u002FCHANGELOG",{"title":1127,"path":1128,"stem":1129,"children":1291,"page":980},[1292],{"title":1293,"path":1294,"stem":1295},"@welldot\u002Frender","\u002Frender\u002Fchangelog","render\u002FCHANGELOG",{"title":1181,"path":1182,"stem":1183,"children":1297,"page":980},[1298],{"title":39,"path":1299,"stem":1300},"\u002Futils\u002Fchangelog","utils\u002FCHANGELOG",1793050495499]