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);
@@ -109,11 +171,11 @@ public class ForecastProcessor implements Runnable {
try try
{ {
byte val = Byte.parseByte(n.getTextContent().trim()); byte val = Byte.parseByte(n.getTextContent().trim());
if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high")) if (XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high"))
{ {
hi = val; hi = val;
} }
else if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low")) else if (XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
{ {
lo = val; lo = val;
} }
@@ -136,45 +198,49 @@ 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
{
dayForecasts[dayIndex].percipPercent = (dayForecasts[dayIndex].percipPercent + percip) - (percip * dayForecasts[dayIndex].percipPercent) / 100F;
}
}
} }
else else
{ {
dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, ValueCheck.NO_DATA_FLOAT); dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, percip);
} }
} }
} }
} }
} for (int i = 0; i < dayForecasts.length; i++)
catch (IOException e)
{
e.printStackTrace();
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(is);
}
for (int i = 0; i < dayForecasts.length; i++)
{
if (dayForecasts[i] == null)
{ {
dayForecasts[i] = new DayForecast(); if (dayForecasts[i] == null)
{
dayForecasts[i] = new DayForecast();
}
} }
TownForecast tf = new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts);
townForecasts.add(tf);
this.processHourlyForecast(tf, doc);
} }
townForecasts.add(new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts));
} }
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

@@ -17,16 +17,15 @@ public class XMLUtils {
if (l.getLength() > 0) if (l.getLength() > 0)
{ {
Node attrib = l.item(0).getAttributes().getNamedItem(attribute); Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
if(attrib != null) if (attrib != null)
return attrib.getTextContent(); return attrib.getTextContent();
} }
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)
return attrib.getTextContent(); return attrib.getTextContent();
return null; return 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,5 +1,6 @@
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,
A few clouds,Few,Clouds A few clouds,Few,Clouds
A mix of sun and cloud,Partly,Cloudy A mix of sun and cloud,Partly,Cloudy
@@ -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
Can't render this file because it has a wrong number of fields in line 13.