Skip to content

Commit

Permalink
Revert "Release 3.0"
Browse files Browse the repository at this point in the history
This reverts commit b773030.
  • Loading branch information
gvdhoven committed Jun 4, 2021
1 parent 56053dd commit 846bec6
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 34 deletions.
8 changes: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ $ npm install node-red-contrib-dutch-weather

For all nodes, you'll need to create at least one configuration. Drag one of the exposed nodes to your flow and set it up just like all other config nodes. After that, you can use the event emitters in your own code.

## Release 3.0.0

* Fixed issue where `prediction` field was not present in rain-data payload.
* Node `dutch-weather-meteoplaza` was **removed**: Meteoplaza has been acquired by Buienradar and the original API used in this code is no longer accessible. You should decide yourself if you are going to keep using this node for rain prediction (since it is still based on both Buienalarm and Buienradar)


## Release 2.0.7

* Added 'lastUpdate' field.
Expand All @@ -40,7 +34,7 @@ For all nodes, you'll need to create at least one configuration. Drag one of the

## Release 2.0.3

* Node `dutch-weather-sun-position` (and) `dutch-weather-solar-events` **removed**: There is a much better node-red node you can use: [node-red-contrib-sun-position](https://flows.nodered.org/node/node-red-contrib-sun-position/)
* `dutch-weather-sun-position` (and) `dutch-weather-solar-events` **removed**: There is a much better node-red node you can use: [node-red-contrib-sun-position](https://flows.nodered.org/node/node-red-contrib-sun-position/)
* **Automatic refresh removed**: The javascript timers sometimes stopped working, which in the worst case led to rain being reported while it was already dry for days; since Node-red has timer nodes built in, i've removed the javascript timers from the code completely. In order to get updated data you have to send a message on the input of a node **with payload** `{ trigger: true }` for it to update.

## Release 2.0.0
Expand Down
39 changes: 39 additions & 0 deletions dutch-weather.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,43 @@
return 'Rain state';
}
})
</script>



<!-- Meteoplaza node -->

<script type="text/x-red" data-template-name="dutch-weather-meteoplaza">
<div class="form-row">
<label for="node-input-conf"><i class="fa fa-map-marker"></i> Location configuration</label>
<input type="text" id="node-input-conf">
</div>
<div class="form-row">
<input type="hidden" id="node-input-name">
</div>
<div class="form-row">
<input type="hidden" id="node-input-topic">
</div>
</script>

<script type="text/x-red" data-help-name="dutch-weather-meteoplaza">
<p>Provides information from the Dutch provider Meteoplaza at the interval defined in the configuration node.</p>
</script>

<script type="text/javascript">
RED.nodes.registerType('dutch-weather-meteoplaza', {
category: 'Dutch_Weather',
defaults: {
conf: { value: '', type: 'dutch-weather-conf', required: true },
name: { },
topic: { }
},
inputs: 1,
outputs: 1,
color: '#528B8B',
icon: 'font-awesome/fa-newspaper-o',
label: function() {
return 'Meteoplaza';
}
})
</script>
27 changes: 27 additions & 0 deletions dutch-weather.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,31 @@ module.exports = function(RED) {
});
}
RED.nodes.registerType("dutch-weather-rain-state", dutchWeatherRainState);



/**
* Meteo events node
*/
function dutchWeatherMeteoplaza(n) {
RED.nodes.createNode(this, n);
this.conf = RED.nodes.getNode(n.conf);

if (!this.conf) {
return null;
}

var node = this;
this.conf.weatherLogic.on('meteoplaza', function (meteoplaza) {
node.send({ 'topic': 'meteoplaza', 'payload': meteoplaza });
});

node.on('input', function(msg) {
if (msg && msg.hasOwnProperty('payload') && (msg.payload.trigger == true)) {
node.conf.weatherLogic.updateMeteoplaza(true);
}
});

}
RED.nodes.registerType("dutch-weather-meteoplaza", dutchWeatherMeteoplaza);
}
143 changes: 143 additions & 0 deletions lib/Meteoplaza.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
'use strict';

const Fetch = require('node-fetch');
const Moment = require('moment');

module.exports = class Meteoplaza {

constructor(lat, lng) {
this.lat = parseFloat(lat).toFixed(2) * 100;
this.lng = parseFloat(lng).toFixed(2) * 100;
this.forecast = { updated: null, parsed: null };
}

getHourlyData(json) {
return {
"icon": json.WXCO_EXTENDED,
"temp": json.TTTT,
"tempFeelsLike": json.FEELS_LIKE,
"sunProbability": parseFloat(json.SSSP),
"precipitation": json.RRRR * ((json.TTTT < 0) ? 10 : 1),
"pressure": json.PPPP,
"humidity": json.RHRH,
"cloudCoverage": parseFloat(json.NNNN),
"wind": {
"direction": json.DDDD,
"speed": json.FFFF,
"speedMs": json.FFFF_MS,
"speedKmh": json.FFFF_KMH
}
};
}

async update() {
// Check if we still have data
var now = new Date();
var getNewForecast = true;

// Data is only updated once every 10 minutes, doesn't make sense to retrieve it before it changes, so we take 245 seconds (4 minutes and 5 seconds)
if (this.forecast.updated != null) {
var rounded = new Date(Math.ceil(this.forecast.updated.getTime() / 604800) * 604800);
getNewForecast = (now >= rounded);
}

if (this.forecast.parsed == null) {
getNewForecast = true;
}

if (!getNewForecast) {
//Helper.Debug('getForecasts()::Used cached data');
return this.forecast.parsed;
}

try {
// Fetch new data
var url = `https://api.meteoplaza.com/v2/meteo/completelocation/${this.lat}.${this.lng}?lang=nl`;
const response = await Fetch(url);
const json = await response.json();
let today = now.getUTCFullYear() + '-' + ('0' + (now.getMonth() + 1)).slice(-2) + '-' + ('0' + now.getDate()).slice(-2);

// Parse if needed
//Helper.Debug('getForecasts()::Got new data - ' + url);

// Parse the forecasts
let startTime = new Date(Moment(json.start_human, 'HH:mm'));

// Parse if needed
var newData = this.forecast.parsed;
if (newData == null) {
newData = {
"now": {
"temp": null,
"tempFeelsLike": null,
"pressure": null,
"humidity": null,
"wind": {
"direction": '',
"speed": null,
"speedMs": null,
"speedKmh": null
}
},
"today": {
"tempMin": null,
"tempMax": null,
"astro": {
"currentTime": null,
"sunRise": null,
"sunSet": null,
"dayLength": null,
"dayLengthDiff": null,
"moonPhase":{
"newMoon": null,
"fullMoon": null,
"firstQuarter": null,
"lastQuarter": null
}
},
"dataPerHour": new Map()
}
};
}

// Astro events
newData.today.astro ={
"currentTime": json.Astro.CurrentTime_ISO,
"sunRise": json.Astro.SunRise_ISO,
"sunSet": json.Astro.SunSet_ISO,
"dayLengthHrs": json.Astro.DayLength,
"moonPhase":{
"newMoon": json.Astro.MoonPhase.NM,
"fullMoon": json.Astro.MoonPhase.VM,
"firstQuarter": json.Astro.MoonPhase.EK,
"lastQuarter": json.Astro.MoonPhase.LK
}
};

// Update hourly temperatures in case something changes
json.Hourly.forEach((hour) => {
if (hour.ValidDt.substring(0, 10) == today) {
var key = hour.ValidDt.substring(11, 13);
newData.today.dataPerHour[key] = this.getHourlyData(hour);

// Calculate min/max temps
newData.today.tempMin = (newData.today.tempMin == null) ? newData.today.dataPerHour[key].temp : Math.min(newData.today.tempMin, newData.today.dataPerHour[key].temp);
newData.today.tempMax = (newData.today.tempMax == null) ? newData.today.dataPerHour[key].temp : Math.max(newData.today.tempMax, newData.today.dataPerHour[key].temp);
}
});

// Get current data
var currentHr = json.Astro.CurrentTime.substr(0,2);
newData.now = newData.today.dataPerHour[currentHr];

// Set new data
this.forecast.parsed = newData;
this.forecast.updated = Moment(response.headers.Date).toDate();
} catch(e) {
console.log(e);
}

// Save & parse forcecast
return this.forecast.parsed;
}
}
44 changes: 23 additions & 21 deletions lib/WeatherLogic.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const isEqual = require('lodash.isequal');

const Buienalarm = require('./Buienalarm');
const Buienradar = require('./Buienradar');
const Meteoplaza = require('./Meteoplaza');

const RAIN_LIGHT = 0.2;
const RAIN_MODERATE = 1;
Expand All @@ -24,10 +25,13 @@ class WeatherLogic extends EventEmitter {

this.rainTimer = null;
this.rainState = null;
this.meteoplaza = null;
this.meteoplazaTimer = null;

// Initialize providers
this.Buienalarm = new Buienalarm(lat, lng);
this.Buienradar = new Buienradar(lat, lng);
this.Meteoplaza = new Meteoplaza(lat, lng);
}

/**
Expand Down Expand Up @@ -171,7 +175,6 @@ class WeatherLogic extends EventEmitter {
var tempState = { lastUpdate: after };

// Loop over possibilities for rain starting or stopping in the next 120 minutes
var stateAtTime;
for (let i = 0; i < 23; i++) {
// Calculate minutes
let inMinutes = i * 5;
Expand Down Expand Up @@ -204,7 +207,7 @@ class WeatherLogic extends EventEmitter {
}

// First loop we set the 'current' state
stateAtTime = this.rainStatePayload(atTime, inMinutes, buienradarPrecipitation, buienalarmPrecipitation);
var stateAtTime = this.rainStatePayload(atTime, inMinutes, buienradarPrecipitation, buienalarmPrecipitation);
if (!tempState.hasOwnProperty('now')) {
tempState.now = stateAtTime;
}
Expand All @@ -218,28 +221,27 @@ class WeatherLogic extends EventEmitter {

// Only emit in case we have data
if (tempState.hasOwnProperty('now')) {
// If we still don't have a 'prediction' then that means that, according to our data, nothing will change.
if (!tempState.hasOwnProperty('prediction')) {
tempState.prediction = stateAtTime;
}

// Fix the prediction message
var dt = this.iso8601dateTime(atTime);
var msg = (tempState.prediction.probability == 100) ? 'It ' : 'There is a ' + tempState.prediction.probability + '% chance that it ';
msg+= ((tempState.prediction.inMinutes > 0) ? 'will be' : 'is') + ' ' + tempState.prediction.state;
msg+= (tempState.now.state === tempState.prediction.state) ? ' for at least ' : ' in ';
if (tempState.prediction.inMinutes > 0) {
msg+= tempState.prediction.inMinutes + ' minutes from now, ';
msg+= ((tempState.now.state === tempState.prediction.state) ? 'untill' : 'at') + ' ';
msg+= dt.substring(0, 10) + ' at ' + dt.substring(11, 19);
}
msg+= '.';
tempState.prediction.message = msg;

// Send updates
this.rainStateUpdate(tempState, force || false);
}
}

/**
* Retreives new information from Meteoplaza
*
* @param boolean Force update?
*/
async updateMeteoplaza(force) {
force = force || false;
let lastUpdated = null;
if (this.meteoplaza !== null)
lastUpdated = this.meteoplaza.updated;
this.meteoplaza = await this.Meteoplaza.update();

// Notify in case we have a new update
if (force || (lastUpdated == null) || (this.meteoplaza.updated > lastUpdated)) {
this.emit('meteoplaza', this.meteoplaza);
}
}
}

module.exports = WeatherLogic;
14 changes: 8 additions & 6 deletions local-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ console.log('* Watchting the weather ...');
var Weather = new WeatherLogic(51.42408, 5.442794);

Weather.on('rain-state', function (prediction) {
if (prediction === null) {
console.log('* Rain state update: invalid result!');
return;
}
console.log('* Rain state update:');
console.log(' - ' + JSON.stringify(prediction, null, '\t'));

console.log(' - ' + JSON.stringify(prediction));
});

Weather.on('meteoplaza', function (meteoplaza) {
console.log('* Meteoplaza update:');
console.log(' - ' + JSON.stringify(meteoplaza));
});

Weather.startMonitor();
setTimeout(function() { Weather.checkRain(); }, 1000);
setTimeout(function() { Weather.updateMeteoplaza(); }, 1000);

0 comments on commit 846bec6

Please sign in to comment.