This commit is contained in:
Flare Microsystems
2024-03-15 23:45:13 -07:00
parent 37c506249a
commit 88a566dcbe
5 changed files with 182 additions and 49 deletions

View File

@@ -6,6 +6,7 @@ import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import com.flaremicro.util.Util; import com.flaremicro.util.Util;
@@ -35,8 +36,11 @@ public class CanadaDatamartProvider extends ForecastProvider {
BufferedReader bufferedReader = null; BufferedReader bufferedReader = null;
try try
{ {
HashSet<String> byCodes = new HashSet<String>(Arrays.asList(byCode.split(","))); ArrayList<String> byCodesArray = new ArrayList<String>(Arrays.asList(byCode.split(",")));
HashSet<String> byNameAndProvinces = new HashSet<String>(Arrays.asList(byNameAndProvince.split(";"))); ArrayList<String> byNameAndProvincesArray = new ArrayList<String>(Arrays.asList(byNameAndProvince.split(";")));
HashSet<String> byCodes = new HashSet<String>(byCodesArray);
HashSet<String> byNameAndProvinces = new HashSet<String>(byNameAndProvincesArray);
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv"); URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv");
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream())); bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String line; String line;
@@ -51,12 +55,21 @@ public class CanadaDatamartProvider extends ForecastProvider {
String[] data = line.trim().split(","); String[] data = line.trim().split(",");
if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase())) if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
{ {
int priority = Integer.MAX_VALUE;
if(byCodes.contains(data[0].toLowerCase()))
{
priority = byCodesArray.indexOf(data[0]);
}
else if(byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
{
priority = byNameAndProvincesArray.indexOf(data[1].toLowerCase() + "," + data[2].toLowerCase());
}
String code = data[0].trim(); String code = data[0].trim();
String town = data[1].trim(); String town = data[1].trim();
String province = data[2].trim(); String province = data[2].trim();
float latitude = Float.parseFloat(data[3].trim().substring(0, data[3].length()-1)); float latitude = Float.parseFloat(data[3].trim().substring(0, data[3].length()-1));
float longitude = Float.parseFloat(data[4].trim().substring(0, data[4].length()-1)); float longitude = Float.parseFloat(data[4].trim().substring(0, data[4].length()-1));
towns.add(new TownInfo(code, town, province, latitude, longitude)); towns.add(new TownInfo(code, town, province, latitude, longitude, priority));
} }
} }
} }
@@ -69,8 +82,12 @@ public class CanadaDatamartProvider extends ForecastProvider {
{ {
Util.cleanClose(bufferedReader); Util.cleanClose(bufferedReader);
} }
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0])); Collections.sort(towns);
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0]), this);
forecastProcessor.processForecasts(); forecastProcessor.processForecasts();
this.getRenderPanel().notifyForecastProviderUpdate();
forecastProcessor.begin();
this.notifyForecastProviderUpdate();
ready = true; ready = true;
} }
@@ -86,6 +103,7 @@ public class CanadaDatamartProvider extends ForecastProvider {
@Override @Override
public void deinit() { public void deinit() {
forecastProcessor.end();
propertyManager.store(); propertyManager.store();
} }

View File

@@ -3,9 +3,14 @@ package com.flaremicro.visualforecast.datamart;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
@@ -22,11 +27,13 @@ import org.xml.sax.SAXException;
import com.flaremicro.util.Util; import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.forecast.DayForecast; import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.HourlyForecast;
import com.flaremicro.visualforecast.forecast.TownForecast; import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.forecast.ValueCheck; import com.flaremicro.visualforecast.forecast.ValueCheck;
public class ForecastProcessor implements Runnable { public class ForecastProcessor implements Runnable {
private final TownInfo[] towns; private final TownInfo[] towns;
private final CanadaDatamartProvider cdp;
private ForecastDetails mostRecentForecast = null; private ForecastDetails mostRecentForecast = null;
private boolean running = false; private boolean running = false;
private Thread self; private Thread self;
@@ -34,9 +41,9 @@ public class ForecastProcessor implements Runnable {
private DatamartTranslation dmt = new DatamartTranslation(); private DatamartTranslation dmt = new DatamartTranslation();
public ForecastProcessor(TownInfo[] towns) { public ForecastProcessor(TownInfo[] towns, CanadaDatamartProvider cdp) {
this.towns = towns; this.towns = towns;
this.cdp = cdp;
try try
{ {
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
@@ -70,20 +77,74 @@ public class ForecastProcessor implements Runnable {
return -1; return -1;
} }
public void processHourlyForecast(TownForecast forecast, Document doc) {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
NodeList hourlyForecast = doc.getElementsByTagName("hourlyForecast");
ArrayList<HourlyForecast> hourlyForecastArray = new ArrayList<HourlyForecast>(12);
for (int i = 0; i < hourlyForecast.getLength(); i++)
{
if (hourlyForecast.item(i).getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) hourlyForecast.item(i);
byte iconCode = dmt.icon(XMLUtils.getIntFromTag(element, "iconCode", ValueCheck.NO_DATA_INT));
byte temp = XMLUtils.getByteFromTag(element, "temperature", ValueCheck.NO_DATA_BYTE);
byte windChill = XMLUtils.getByteFromTag(element, "windChill", ValueCheck.NO_DATA_BYTE);
float percip = XMLUtils.getFloatFromTag(element, "lop", ValueCheck.NO_DATA_FLOAT);
String dateTimeUTC = XMLUtils.getStringFromAttribute(element, "dateTimeUTC");
if (dateTimeUTC != null)
{
try
{
Date date = dateFormat.parse(dateTimeUTC);
hourlyForecastArray.add(new HourlyForecast(date, iconCode, temp, (short) 0, percip, windChill));
}
catch (ParseException e)
{
e.printStackTrace();
}
}
}
}
forecast.setHourlyForecast(hourlyForecastArray.toArray(new HourlyForecast[0]));
}
public void processForecasts() { public void processForecasts() {
System.out.println("Time to update");
ForecastDetails forecastDetails = new ForecastDetails(); ForecastDetails forecastDetails = new ForecastDetails();
ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>(); ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>();
for (TownInfo townInfo : towns) for (TownInfo townInfo : towns)
{ {
DayForecast[] dayForecasts = new DayForecast[8]; DayForecast[] dayForecasts = new DayForecast[8];
InputStream is = null; InputStream is = null;
Document doc = null;
try try
{ {
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/BC/" + townInfo.code + "_e.xml"); URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/" + townInfo.province + "/" + townInfo.code + "_e.xml");
DocumentBuilder db = dbf.newDocumentBuilder(); DocumentBuilder db = dbf.newDocumentBuilder();
is = url.openStream(); is = url.openStream();
Document doc = db.parse(is); doc = db.parse(is);
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(is);
}
if (doc != null)
{
NodeList nodeList = doc.getElementsByTagName("forecast"); NodeList nodeList = doc.getElementsByTagName("forecast");
for (int i = 0; i < nodeList.getLength(); i++) for (int i = 0; i < nodeList.getLength(); i++)
{ {
@@ -92,7 +153,8 @@ public class ForecastProcessor implements Runnable {
Element node = (Element) nodeList.item(i); Element node = (Element) nodeList.item(i);
int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName")); int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName"));
Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast"); Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast");
int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", 0); int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", ValueCheck.NO_DATA_INT);
float percip = XMLUtils.getFloatFromTag(abbForecast, "pop", ValueCheck.NO_DATA_FLOAT);
String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary"); String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary");
WeatherLines lines = dmt.weatherName(textForecast); WeatherLines lines = dmt.weatherName(textForecast);
@@ -136,31 +198,24 @@ public class ForecastProcessor implements Runnable {
{ {
dayForecasts[dayIndex].hiTemp = hi; dayForecasts[dayIndex].hiTemp = hi;
} }
if (!ValueCheck.valueNoData(percip))
{
if (ValueCheck.valueNoData(dayForecasts[dayIndex].percipPercent))
{
dayForecasts[dayIndex].percipPercent = percip;
} }
else else
{ {
dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, ValueCheck.NO_DATA_FLOAT); dayForecasts[dayIndex].percipPercent = (dayForecasts[dayIndex].percipPercent + percip) - (percip * dayForecasts[dayIndex].percipPercent) / 100F;
} }
} }
} }
} else
}
catch (IOException e)
{ {
e.printStackTrace(); dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, percip);
} }
catch (ParserConfigurationException e)
{
e.printStackTrace();
} }
catch (SAXException e)
{
e.printStackTrace();
} }
finally
{
Util.cleanClose(is);
} }
for (int i = 0; i < dayForecasts.length; i++) for (int i = 0; i < dayForecasts.length; i++)
{ {
@@ -169,12 +224,23 @@ public class ForecastProcessor implements Runnable {
dayForecasts[i] = new DayForecast(); dayForecasts[i] = new DayForecast();
} }
} }
townForecasts.add(new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts)); TownForecast tf = new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts);
townForecasts.add(tf);
this.processHourlyForecast(tf, doc);
}
} }
forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0])); forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0]));
setMostRecentForecast(forecastDetails); setMostRecentForecast(forecastDetails);
} }
public void begin() {
if (!running)
{
running = true;
new Thread(this).start();
}
}
public void end() { public void end() {
running = false; running = false;
self.interrupt(); self.interrupt();
@@ -201,8 +267,14 @@ public class ForecastProcessor implements Runnable {
{ {
try try
{ {
Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS)); long hourInMillis = 60 * 60 * 1000;
long startDateInMillis = System.currentTimeMillis();
long millisSinceLastHourChange = startDateInMillis % hourInMillis;
long millisToNextHourChange = hourInMillis - millisSinceLastHourChange;
Thread.sleep(millisToNextHourChange);
processForecasts(); processForecasts();
this.cdp.notifyForecastProviderUpdate();
//Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
} }
catch (InterruptedException e) catch (InterruptedException e)
{ {

View File

@@ -1,17 +1,24 @@
package com.flaremicro.visualforecast.datamart; package com.flaremicro.visualforecast.datamart;
public class TownInfo { public class TownInfo implements Comparable<TownInfo> {
public final String code; public final String code;
public final String townName; public final String townName;
public final String province; public final String province;
public final float northLat; public final float northLat;
public final float westLong; public final float westLong;
public final int priority;
public TownInfo(String code, String townName, String province, float northLat, float westLong) { public TownInfo(String code, String townName, String province, float northLat, float westLong, int priority) {
this.code = code; this.code = code;
this.townName = townName; this.townName = townName;
this.province = province; this.province = province;
this.northLat = northLat; this.northLat = northLat;
this.westLong = westLong; this.westLong = westLong;
this.priority = priority;
}
@Override
public int compareTo(TownInfo o) {
return priority - o.priority;
} }
} }

View File

@@ -23,7 +23,6 @@ public class XMLUtils {
return null; return null;
} }
public static String getStringFromAttribute(Node n, String attribute) { public static String getStringFromAttribute(Node n, String attribute) {
Node attrib = n.getAttributes().getNamedItem(attribute); Node attrib = n.getAttributes().getNamedItem(attribute);
if (attrib != null) if (attrib != null)
@@ -41,8 +40,10 @@ public class XMLUtils {
return null; return null;
} }
public static Integer getIntFromTag(Element abbForecast, String tag, Integer fallback) { public static Integer getIntFromTag(Element parent, String tag, Integer fallback) {
String content = getStringFromTag(abbForecast, tag); String content = getStringFromTag(parent, tag);
if(content == null || content.length() == 0)
return fallback;
try try
{ {
return Integer.parseInt(content); return Integer.parseInt(content);
@@ -53,4 +54,34 @@ public class XMLUtils {
} }
return fallback; return fallback;
} }
public static float getFloatFromTag(Element parent, String tag, float fallback) {
String content = getStringFromTag(parent, tag);
if(content == null || content.length() == 0)
return fallback;
try
{
return Float.parseFloat(content);
}
catch (NumberFormatException ex)
{
}
return fallback;
}
public static byte getByteFromTag(Element parent, String tag, Byte fallback) {
String content = getStringFromTag(parent, tag);
if(content == null || content.length() == 0)
return fallback;
try
{
return Byte.parseByte(content);
}
catch (NumberFormatException ex)
{
}
return fallback;
}
} }

View File

@@ -1,3 +1,4 @@
Flurries or rain showers,Flurries/,Showers
Mainly sunny,Mainly,Sunny Mainly sunny,Mainly,Sunny
Mainly cloudy,Mainly,Cloudy Mainly cloudy,Mainly,Cloudy
Sunny,Sunny, Sunny,Sunny,
@@ -9,12 +10,15 @@ Cloudy with sunny periods,Sunny,Periods
Increasing cloudiness,Increasing,Clouds Increasing cloudiness,Increasing,Clouds
Clearing,Clearing, Clearing,Clearing,
Clear,Sun, Clear,Sun,
partly cloudy,Partly,Cloudy,
showers or drizzle,Showers/,Drizzle
Chance of showers,Chance,Showers Chance of showers,Chance,Showers
A few showers,Few,Showers A few showers,Few,Showers
Chance of drizzle or rain,Chance,Drizzle Chance of drizzle or rain,Chance,Drizzle
A few flurries or rain showers,Flurries/,Showers A few flurries or rain showers,Flurries/,Showers
Chance of flurries or rain showers,Flurries/,Showers Chance of flurries or rain showers,Flurries/,Showers
Chance of rain showers or flurries,Flurries/,Showers Chance of rain showers or flurries,Showers/Flurries
chance of rain showers or wet flurries,Showers/,Flurries
A few flurries,Flurries, A few flurries,Flurries,
Chance of flurries,Chance,Flurries Chance of flurries,Chance,Flurries
A few wet flurries,Wet,Flurries A few wet flurries,Wet,Flurries
@@ -97,3 +101,4 @@ Chance of thunderstorms,Thunder,Storms
Snow and blowing snow,Blowing,Snow Snow and blowing snow,Blowing,Snow
Windy,Windy Windy,Windy
Smoke,Smoke Smoke,Smoke
rain showers or flurries,Showers/,Flurries
1 Mainly sunny Flurries or rain showers Mainly Flurries/ Sunny Showers
1 Flurries or rain showers Flurries/ Showers
2 Mainly sunny Mainly sunny Mainly Mainly Sunny Sunny
3 Mainly cloudy Mainly cloudy Mainly Mainly Cloudy Cloudy
4 Sunny Sunny Sunny Sunny
10 Increasing cloudiness Increasing cloudiness Increasing Increasing Clouds Clouds
11 Clearing Clearing Clearing Clearing
12 Clear Clear Sun Sun
13 partly cloudy Partly Cloudy
14 showers or drizzle Showers/ Drizzle
15 Chance of showers Chance of showers Chance Chance Showers Showers
16 A few showers A few showers Few Few Showers Showers
17 Chance of drizzle or rain Chance of drizzle or rain Chance Chance Drizzle Drizzle
18 A few flurries or rain showers A few flurries or rain showers Flurries/ Flurries/ Showers Showers
19 Chance of flurries or rain showers Chance of flurries or rain showers Flurries/ Flurries/ Showers Showers
20 Chance of rain showers or flurries Chance of rain showers or flurries Flurries/ Showers/Flurries Showers
21 chance of rain showers or wet flurries Showers/ Flurries
22 A few flurries A few flurries Flurries Flurries
23 Chance of flurries Chance of flurries Chance Chance Flurries Flurries
24 A few wet flurries A few wet flurries Wet Wet Flurries Flurries
101 Snow and blowing snow Snow and blowing snow Blowing Blowing Snow Snow
102 Windy Windy Windy Windy
103 Smoke Smoke Smoke Smoke
104 rain showers or flurries Showers/ Flurries