Skip to content
Snippets Groups Projects
Commit 6e7f19a8 authored by Tor-Einar Skog's avatar Tor-Einar Skog
Browse files

Added FruitWebDavisDataParser

parent a8e713dc
No related branches found
No related tags found
No related merge requests found
target/
classes/
*~
/nbproject/
\ No newline at end of file
/*
* Copyright (c) 2016 NIBIO <http://www.nibio.no/>.
*
* This file is part of VIPSLogic.
* VIPSLogic is free software: you can redistribute it and/or modify
* it under the terms of the NIBIO Open Source License as published by
* NIBIO, either version 1 of the License, or (at your option) any
* later version.
*
* VIPSLogic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* NIBIO Open Source License for more details.
*
* You should have received a copy of the NIBIO Open Source License
* along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
*
*/
package no.nibio.vips.util.weather;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import no.nibio.vips.entity.WeatherObservation;
/**
* Reads/parses data from a Davis weather station using the fruitweb service: http://www.fruitweb.info/
* @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
* @author Tor-Einar Skog <tor-einar.skog@nibio.no>
*/
public class FruitWebDavisDataParser {
// Sample: http://wds.fruitweb.info/sc/getFile.php?id=283&date=2016-01-01&pw=Kghr528Ub5
// id and password combined must be the "remote ID" in VIPSLogic form
public final static String FRUITWEB_URL_TEMPLATE = "http://wds.fruitweb.info/sc/getFile.php?{0}&date={1}";
// Metos parameters, including name and aggregation type
private final static String[][] ELEMENT_MEASUREMENT_TYPES = {
{"RAIN","RR","SUM"},
{"LW1","BT","SUM"},
{"AIRTEMP","TM","AVG"},
{"AIRHUM","UM","AVG"}
};
/**
* Using output designed for RIMPro, parsing into WeatherObservations
* @param stationID the METOS station ID
* @param timeZone
* @return
*/
public List<WeatherObservation> getWeatherObservations(String stationID, TimeZone timeZone, Date startDate) throws ParseWeatherDataException
{
List<WeatherObservation> retVal = new ArrayList<>();
SimpleDateFormat urlDFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
dFormat.setTimeZone(timeZone);
// Assuming 1 hour resolution until we find a timestamp that says :30
Integer logIntervalId = WeatherObservation.LOG_INTERVAL_ID_1H;
List<String[]> data = new ArrayList<>();
String[] headers;
Map<Integer, Integer> elementOrdering = new HashMap<>();
try {
URL metosURL = new URL(MessageFormat.format(FruitWebDavisDataParser.FRUITWEB_URL_TEMPLATE, stationID,urlDFormat.format(startDate)));
BufferedReader in = new BufferedReader(
new InputStreamReader(metosURL.openStream()));
String inputLine;
Date testTimestamp;
// We need to collect all the lines first, because we need to analyze
// If the resolution is 30 minutes or 1 hour
while ((inputLine = in.readLine()) != null)
{
String[] lineData = inputLine.split(";");
// Skip empty lines
if(lineData.length <= 1)
{
continue;
}
// Check for valid start of line
try {
testTimestamp = dFormat.parse(lineData[0] + " " + lineData[1]);
data.add(lineData);
if(lineData[1].split(":")[1].equals("30"))
{
logIntervalId = WeatherObservation.LOG_INTERVAL_ID_30M;
}
} catch (ParseException ex) {
// Is this the heading line?
// Then we parse it to set the ordering of elements
if(lineData[0].equals("DATE"))
{
headers = lineData;
// DATE and TIME should always be the two first ones
for(int i=2;i<lineData.length;i++)
{
for(int j=0;j<ELEMENT_MEASUREMENT_TYPES.length;j++)
{
if(ELEMENT_MEASUREMENT_TYPES[j][0].equals(lineData[i]))
{
elementOrdering.put(i,j);
}
}
}
}
}
}
in.close();
} catch (IOException ex) {
throw new ParseWeatherDataException(ex.getMessage());
}
// Data comes in half-hour chunks (resolution = 30 minutes)
if(logIntervalId.equals(WeatherObservation.LOG_INTERVAL_ID_30M))
{
Boolean shouldBe00Now = true;
String[] data00 = null;
String[] data30 = null;
Date timestamp = null;
for(String[] lineData: data)
{
// Skip lines that are not exactly :00 or :30
if(
!lineData[1].split(":")[1].equals("00")
&& ! lineData[1].split(":")[1].equals("30")
)
{
continue;
}
else if(lineData[1].split(":")[1].equals("00") && shouldBe00Now)
{
data00 = lineData;
try
{
timestamp = dFormat.parse(lineData[0] + " " + lineData[1]);
}
catch(ParseException ex)
{
throw new ParseWeatherDataException("Error with time stamp in weather data from Davis/FruitWeb station: " + ex.getMessage());
}
shouldBe00Now = false;
continue; // So that we summarize only after :30 data has been set too
}
else if(lineData[1].split(":")[1].equals("30") && !shouldBe00Now)
{
data30 = lineData;
shouldBe00Now = true;
}
else
{
throw new ParseWeatherDataException("Doesn't make sense!");
}
for(Integer i=2;i<data00.length;i++)
{
Double aggregateValue = null;
Double value00 = Double.valueOf(data00[i].replaceAll(",","."));
Double value30 = Double.valueOf(data30[i].replaceAll(",","."));
Integer elementMeasurementTypeIndex = elementOrdering.get(i);
// This means there is an element type we don't collect
if(elementMeasurementTypeIndex == null)
{
continue;
}
//System.out.println("element " + i + "=" + MetosDataParser.elementMeasurementTypes[elementMeasurementTypeIndex][1]);
if(FruitWebDavisDataParser.ELEMENT_MEASUREMENT_TYPES[elementMeasurementTypeIndex][2].equals("AVG"))
{
aggregateValue = (value00 + value30) / 2;
}
else
{
aggregateValue = (value00 + value30);
}
WeatherObservation obs = new WeatherObservation();
obs.setTimeMeasured(timestamp);
obs.setLogIntervalId(WeatherObservation.LOG_INTERVAL_ID_1H);
obs.setElementMeasurementTypeId(FruitWebDavisDataParser.ELEMENT_MEASUREMENT_TYPES[elementMeasurementTypeIndex][1]);
obs.setValue(aggregateValue);
retVal.add(obs);
}
}
}
// Data is hourly, easy to add
else
{
Date timestamp = null;
for(String[] lineData: data)
{
// If minute != 00 we skip the line
if(!lineData[1].split(":")[1].equals("00"))
{
continue;
}
try
{
timestamp = dFormat.parse(lineData[0] + " " + lineData[1]);
}
catch(ParseException ex)
{
throw new ParseWeatherDataException("Error with time stamp in weather data from Metos station: " + ex.getMessage());
}
for(Integer i=2;i<lineData.length;i++)
{
Double value = Double.valueOf(lineData[i].replaceAll(",","."));
Integer elementMeasurementTypeIndex = elementOrdering.get(i);
// This means there is an element type we don't collect
if(elementMeasurementTypeIndex == null)
{
continue;
}
WeatherObservation obs = new WeatherObservation();
obs.setTimeMeasured(timestamp);
obs.setLogIntervalId(WeatherObservation.LOG_INTERVAL_ID_1H);
obs.setElementMeasurementTypeId(FruitWebDavisDataParser.ELEMENT_MEASUREMENT_TYPES[elementMeasurementTypeIndex][1]);
obs.setValue(value);
retVal.add(obs);
}
}
}
return retVal;
}
}
......@@ -58,6 +58,7 @@ public class MetosDataParser {
/**
* Makes sure only data after the requested date is returned
* @param stationID
* @param timeZone
* @param startDate
* @return
* @throws ParseWeatherDataException
......@@ -79,6 +80,7 @@ public class MetosDataParser {
/**
* Using output designed for RIMPro, parsing into WeatherObservations
* @param stationID the METOS station ID
* @param timeZone
* @return
*/
public List<WeatherObservation> getWeatherObservations(String stationID, TimeZone timeZone) throws ParseWeatherDataException
......
/*
* Copyright (c) 2016 NIBIO <http://www.nibio.no/>.
*
* This file is part of VIPSLogic.
* VIPSLogic is free software: you can redistribute it and/or modify
* it under the terms of the NIBIO Open Source License as published by
* NIBIO, either version 1 of the License, or (at your option) any
* later version.
*
* VIPSLogic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* NIBIO Open Source License for more details.
*
* You should have received a copy of the NIBIO Open Source License
* along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
*
*/
package no.nibio.vips.util.weather;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import no.nibio.vips.entity.WeatherObservation;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author treinar
*/
public class FruitWebDavisDataParserTest {
public FruitWebDavisDataParserTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of getWeatherObservations method, of class FruitWebDavisDataParser.
*/
@Test
public void testGetWeatherObservations() throws Exception {
System.out.println("getWeatherObservations");
String stationID = "id=283&pw=Kghr528Ub5";
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance(timeZone);
cal.set(2016, Calendar.JANUARY, 1, 0, 0, 0);
Date startDate = cal.getTime();
FruitWebDavisDataParser instance = new FruitWebDavisDataParser();
List<WeatherObservation> result = instance.getWeatherObservations(stationID, timeZone, startDate);
for(WeatherObservation obs:result)
{
System.out.println(obs);
}
assertNotNull( result);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment