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.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import com.flaremicro.util.Util;
@@ -35,8 +36,11 @@ public class CanadaDatamartProvider extends ForecastProvider {
BufferedReader bufferedReader = null;
try
{
HashSet<String> byCodes = new HashSet<String>(Arrays.asList(byCode.split(",")));
HashSet<String> byNameAndProvinces = new HashSet<String>(Arrays.asList(byNameAndProvince.split(";")));
ArrayList<String> byCodesArray = new ArrayList<String>(Arrays.asList(byCode.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");
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
@@ -51,12 +55,21 @@ public class CanadaDatamartProvider extends ForecastProvider {
String[] data = line.trim().split(",");
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 town = data[1].trim();
String province = data[2].trim();
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));
towns.add(new TownInfo(code, town, province, latitude, longitude));
towns.add(new TownInfo(code, town, province, latitude, longitude, priority));
}
}
}
@@ -69,11 +82,15 @@ public class CanadaDatamartProvider extends ForecastProvider {
{
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();
this.getRenderPanel().notifyForecastProviderUpdate();
forecastProcessor.begin();
this.notifyForecastProviderUpdate();
ready = true;
}
@Override
public ForecastDetails getForecast() {
return forecastProcessor.getMostRecentForecast();
@@ -86,6 +103,7 @@ public class CanadaDatamartProvider extends ForecastProvider {
@Override
public void deinit() {
forecastProcessor.end();
propertyManager.store();
}

View File

@@ -3,9 +3,14 @@ package com.flaremicro.visualforecast.datamart;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import javax.xml.XMLConstants;
@@ -22,11 +27,13 @@ import org.xml.sax.SAXException;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.HourlyForecast;
import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.forecast.ValueCheck;
public class ForecastProcessor implements Runnable {
private final TownInfo[] towns;
private final CanadaDatamartProvider cdp;
private ForecastDetails mostRecentForecast = null;
private boolean running = false;
private Thread self;
@@ -34,9 +41,9 @@ public class ForecastProcessor implements Runnable {
private DatamartTranslation dmt = new DatamartTranslation();
public ForecastProcessor(TownInfo[] towns) {
public ForecastProcessor(TownInfo[] towns, CanadaDatamartProvider cdp) {
this.towns = towns;
this.cdp = cdp;
try
{
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
@@ -70,20 +77,74 @@ public class ForecastProcessor implements Runnable {
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() {
System.out.println("Time to update");
ForecastDetails forecastDetails = new ForecastDetails();
ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>();
for (TownInfo townInfo : towns)
{
DayForecast[] dayForecasts = new DayForecast[8];
InputStream is = null;
Document doc = null;
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();
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");
for (int i = 0; i < nodeList.getLength(); i++)
{
@@ -92,7 +153,8 @@ public class ForecastProcessor implements Runnable {
Element node = (Element) nodeList.item(i);
int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName"));
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");
WeatherLines lines = dmt.weatherName(textForecast);
@@ -109,11 +171,11 @@ public class ForecastProcessor implements Runnable {
try
{
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;
}
else if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
else if (XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
{
lo = val;
}
@@ -136,45 +198,49 @@ public class ForecastProcessor implements Runnable {
{
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
{
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);
}
}
}
}
}
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)
for (int i = 0; i < dayForecasts.length; i++)
{
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]));
setMostRecentForecast(forecastDetails);
}
public void begin() {
if (!running)
{
running = true;
new Thread(this).start();
}
}
public void end() {
running = false;
self.interrupt();
@@ -201,8 +267,14 @@ public class ForecastProcessor implements Runnable {
{
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();
this.cdp.notifyForecastProviderUpdate();
//Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
}
catch (InterruptedException e)
{

View File

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

View File

@@ -11,22 +11,21 @@ public class XMLUtils {
return l.item(0).getTextContent();
return null;
}
public static String getStringFromTagAttribute(Element parent, String tag, String attribute) {
NodeList l = parent.getElementsByTagName(tag);
if (l.getLength() > 0)
{
Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
if(attrib != null)
if (attrib != null)
return attrib.getTextContent();
}
return null;
}
public static String getStringFromAttribute(Node n, String attribute) {
Node attrib = n.getAttributes().getNamedItem(attribute);
if(attrib != null)
if (attrib != null)
return attrib.getTextContent();
return null;
}
@@ -41,15 +40,47 @@ public class XMLUtils {
return null;
}
public static Integer getIntFromTag(Element abbForecast, String tag, Integer fallback) {
String content = getStringFromTag(abbForecast, tag);
public static Integer getIntFromTag(Element parent, String tag, Integer fallback) {
String content = getStringFromTag(parent, tag);
if(content == null || content.length() == 0)
return fallback;
try
{
return Integer.parseInt(content);
}
catch (NumberFormatException ex)
{
}
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 cloudy,Mainly, Cloudy
Mainly cloudy,Mainly,Cloudy
Sunny,Sunny,
A few clouds,Few,Clouds
A mix of sun and cloud,Partly,Cloudy
@@ -9,12 +10,15 @@ Cloudy with sunny periods,Sunny,Periods
Increasing cloudiness,Increasing,Clouds
Clearing,Clearing,
Clear,Sun,
partly cloudy,Partly,Cloudy,
showers or drizzle,Showers/,Drizzle
Chance of showers,Chance,Showers
A few showers,Few,Showers
Chance of drizzle or rain,Chance,Drizzle
A few 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,
Chance of flurries,Chance,Flurries
A few wet flurries,Wet,Flurries
@@ -97,3 +101,4 @@ Chance of thunderstorms,Thunder,Storms
Snow and blowing snow,Blowing,Snow
Windy,Windy
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
5 A few clouds A few clouds Few Few Clouds Clouds
6 A mix of sun and cloud A mix of sun and cloud Partly Partly Cloudy Cloudy
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