diff --git a/dependencies/monster/SpeficicClass.js b/dependencies/monster/SpeficicClass.js new file mode 100644 index 0000000..92952c8 --- /dev/null +++ b/dependencies/monster/SpeficicClass.js @@ -0,0 +1,701 @@ +// add params for scaling in file +// add variables day of year and day of week +// add rain data for built-up areas only + +const EventEmitter = require('events'); +const Logger = require('../../../generalFunctions/helper/logger'); +const defaultConfig = require('./monsterConfig.json'); +const ConfigUtils = require('../../../generalFunctions/helper/configUtils'); +const tf = require('@tensorflow/tfjs'); +const tfLoader = require('./modelLoader'); + +class Monster{ + /*------------------- Construct and set vars -------------------*/ + constructor(config={}) { + + //init + this.init = false; // keep track of init + + this.emitter = new EventEmitter(); // Own EventEmitter + this.configUtils = new ConfigUtils(defaultConfig,config.general.logging.enabled,config.general.logging.logLevel); // ConfigUtils + this.config = this.configUtils.initConfig(config); + + // Init after config is set + this.logger = new Logger(this.config.general.logging.enabled,this.config.general.logging.logLevel, this.config.general.name); + + this.modelLoader = new tfLoader(this.logger); // ModelLoader + + // -------------------------------------- fetch dependencies -------------------------- + this.convert = require('../../../convert/dependencies/index'); + this.math = require('mathjs'); + + this.model = null; // TensorFlow model placeholder + + //place holders for output data + this.output = {} ; // object to place all relevant outputs in and preform event change check on + this.child = {} ; // register childs + + //Specific object info + this.aquonSampleName = "112100" ; // aquon sample name to start automatic sampling on the basis of the document + this.monsternametijden = {} ; // json monsternametijden file? + this.rain_data = {} ; // precipitation data + this.aggregatedOutput = {} ; // object that does not contain momentary values but a combination of all kinds of data over a fixed period of time + this.sumRain = 0 ; // total sum of rain over time window + n hours and - n hours + this.avgRain = 0 ; // total divided by number of locations to get average over total time + this.daysPerYear = 0 ; // how many days remaining for this year + + // outputs + this.pulse = false; // output pulse to sampling machine + this.bucketVol = 0; // how full is the sample? + this.sumPuls = 0; // number of pulses so far + this.predFlow = 0; // predicted flow over sampling time in hours, expressed in m3 + this.bucketWeight = 0; // actual weight of bucket + + //inputs + this.q = 0; // influent flow in m3/h + this.i_start = false // when true, the program gets kicked off calculating what it needs to take samples + this.sampling_time = config.constraints.samplingtime; // time expressed in hours over which the sampling will run (currently 24) + this.emptyWeightBucket = config.asset.emptyWeightBucket; // empty weight of the bucket + + // internal vars + this.temp_pulse = 0; // each interval pulses send out 1 and then reset + this.volume_pulse = 0.05; // define volume pulse expressed in L + this.minVolume = config.constraints.minVolume;// define min volume in a sampling cabinet before a sample is declared valid expressed in L + this.maxVolume = 0; // calculated maxvolume depending on own weight + this.maxWeight = config.constraints.maxWeight;// define max volume in a sampling cabinet before a sample is declared invalid expressed in L + this.cap_volume = 55; // abs max capacity of bucket (volume) in liters + this.targetVolume = 0; // volume of sampling cabinet that model aims for + this.minPuls = 0; // calculates the min pulses depending on min_vol and max_vol + this.maxPuls = 0; // calculates the max pulses depending on min_vol and max_vol + this.absMaxPuls = 0; // capacity of sampling cabinet (number of pulses) + this.targetPuls = 0; // keeps track of the desired amount of pulses (+- 50% tolerance), based on aimed volume + this.m3PerPuls = 0; // each pulse is equal to a number of m3 + this.predM3PerSec = 0; // predicted flow in m3 per second + this.m3PerTick = 0; // actual measured flow in m3 per second + this.m3Total = 0; // total measured flow over sampling time in m3 + this.running = false; // define if sampling is running or not + + this.qLineRaw = {}; // see example + this.minSeen = {}; // keeps track of minimum ever seen so far in a time period for each hour (over totals not every value) + this.maxSeen = {}; // keeps track of maximum ever seen so far in a time period for each hour (over totals not every value) + this.qLineRefined = {}; // this should be the ( quantiles? ) classified in the datasets + this.calcTimeShiftDry = 0; // What is the delay after a dry period of minimum n hours + this.calcTimeShiftWet = 0; + this.calcCapacitySewer = 0; + // how much rain goes to the sewage ? -> calculate surface area of hardend / sewage. + + this.minDryHours = 0; // what is the minimum of dry hours before we can calculate timeshift? spot this with moving average? + this.minWetHours = 0; // how long does it take to remove all the rain? + this.resolution = 0; // Number of chunks in qLineRaw / define how big the window is to sum all values ( for now we need to take 1 hour or bigger resolutions but in the future smaller is better to see more accurate correlations) + this.tmpTotQ = 0; // keep track of sum of q within resolution window + + //old prediction factor + this.predFactor = 0.7; // define factor as multiplier for prediction + + //track program start and stop + this.start_time = Date.now(); // default start time + this.stop_time = Date.now(); // default stop time + this.flowTime = 0; //keep track in detail how much time between 2 ticks for more accurate flow measurement + this.timePassed = 0; // time in seconds + this.timeLeft = 0; // time in seconds + this.currHour = new Date().getHours(); // on init define in which hour we are 0 - 23 + + + this.init = true; // end of constructor + + //set boundries and targets after init based on above settings + this.set_boundries_and_targets(); + + + } + + /*------------------- GETTER/SETTERS Dynamics -------------------*/ + set monsternametijden(value){ + + if(this.init){ + if(Object.keys(value).length > 0){ + + //check if push is in valid format and not null + if( + typeof value[0].SAMPLE_NAME !== 'undefined' + && + typeof value[0].DESCRIPTION !== 'undefined' + && + typeof value[0].SAMPLED_DATE !== 'undefined' + && + typeof value[0].START_DATE !== 'undefined' + && + typeof value[0].END_DATE !== 'undefined' + ){ + + //each time this changes we load the next date applicable for this function + this._monsternametijden = value; + + //fetch dates + this.regNextDate(value); + + } + else{ + // Monsternametijden object Wrong format contact AQUON + } + } + else{ + // Monsternametijden object Wrong format contact AQUON + } + } + } + + get monsternametijden(){ + return this._monsternametijden; + } + + set rain_data(value){ + + //retrieve precipitation expected during the coming day and precipitation of yesterday + this._rain_data = value; + + //only update after init and is not running. + if(this.init && !this.running){ + this.updatePredRain(value); + } + + } + + get rain_data(){ + return this._rain_data; + } + + set bucketVol(val){ + + //Put val in local var + this._bucketVol = val; + + //Place into output object + this.output.bucketVol = val; + + // update bucket weight + this.bucketWeight = val + this.emptyWeightBucket; + } + + get bucketVol(){ + return this._bucketVol; + } + + set minVolume(val){ + + //Protect against 0 + val == 0 ? val = 1 : val = val; + + this._minVolume = val; + + //Place into output object + this.output.minVolume = val; + } + + get minVolume(){ + return this._minVolume; + } + + set q(val){ + + //Put val in local var + this._q = val; + + //Place into output object + this.output.q = val; + this.output.qm3sec = this.convert(val).from('m3/h').to('m3/s'); + + } + + get q(){ + return this._q; + } + + /*------------------- FUNCTIONS -------------------*/ + + set_boundries_and_targets(){ + + // define boundries for algorithm + this.maxVolume = this.maxWeight - this.emptyWeightBucket ; // substract bucket weight of max volume assuming they are both on a 1 to 1 ratio + this.minPuls = Math.round(this.minVolume / this.volume_pulse); // minimum pulses we want before we have a valid sample + this.maxPuls = Math.round(this.maxVolume / this.volume_pulse); // maximum pulses we can handle (otherwise sample is too heavy) + this.absMaxPuls = Math.round(this.cap_volume / this.volume_pulse); // number of pulses a sample can contain before overflowing + // define target values + this.targetVolume = this.minVolume * Math.sqrt(this.maxVolume / this.minVolume); + //old way + //this.targetVolume = Math.round( ( ( (this.maxVolume - this.minVolume) / 2 ) + this.minVolume ) * 100) / 100; // calculate middle between min and max + // correct target values + this.targetPuls = Math.round(this.targetVolume / this.volume_pulse) ; // define desired amount of pulses (in this case our prediction can deviate 50% up and 50% down without a problem) + } + + updateArchiveRain(val){ + + } + + updatePredRain(value){ + //make date objects to define relative time window + let now = new Date(Date.now()); + let past = new Date(Date.now()); + let future = new Date(Date.now()); + let totalRaw = {}; + let totalProb = {}; + let totalAvg = {}; + + //refine object with different values + let rain = {}; + rain.hourly = {}; // an object with timestamps and aggreated over all locations summed precipation in mm + rain.hourly.time = []; + rain.hourly.precipationRaw = []; + rain.hourly.precipationProb = []; + + let numberOfLocations = 0; + + //Make timestamp + 24 hours + future.setHours(now.getHours() + 24); + + //Make timestamp - 24hours + past.setHours(now.getHours() - 24); + + //go through all locations and sum up the average precipation of each location so we have summed precipation over every hour + Object.entries(value).forEach(([locationKey, location],locationindex) => { + + //number of locations + numberOfLocations++; + + // make an object to keep track of the dataset we load + this.aggregatedOutput[locationKey] = {}; + this.aggregatedOutput[locationKey].tag = {}; + this.aggregatedOutput[locationKey].tag.latitude = location.latitude; + this.aggregatedOutput[locationKey].tag.longitude = location.longitude; + this.aggregatedOutput[locationKey].precipationRaw = {}; + this.aggregatedOutput[locationKey].precipationProb = {}; + + + //loop through object for each location over all hourlys + Object.entries(location.hourly.time).forEach(([key, time], index) => { + + this.aggregatedOutput[locationKey].precipationRaw[key] = {}; + this.aggregatedOutput[locationKey].precipationProb[key] = {}; + + //convert string output to a date object + let checkdate = new Date(time); + + //convert date to milliseconds timestamps + let currTimestamp = checkdate.getTime(); + let probability = 100; //default probility unless otherwise defined + + if(typeof location.hourly.precipitation_probability !== 'undefined'){ + probability = location.hourly.precipitation_probability[key]; + + } + + if(probability > 0){ + probability /= 100; + } + + // only interested in dates before timeframe and after to make use of + // ( currTimestamp >= now && currTimestamp < future) || ( currTimestamp < now && currTimestamp > past ) + if( true ){ + + typeof totalRaw[currTimestamp] === 'undefined' ? totalRaw[currTimestamp] = 0 : null; + typeof totalProb[currTimestamp] === 'undefined' ? totalProb[currTimestamp] = 0 : null; + + //placed probability into the equation + totalRaw[currTimestamp] += location.hourly.precipitation[key] ; + totalProb[currTimestamp] += ( location.hourly.precipitation[key] * probability ) ; + + //keep track of all requested data + this.aggregatedOutput[locationKey].precipationRaw[key]["val"] = location.hourly.precipitation[key]; // raw data from open weather data + this.aggregatedOutput[locationKey].precipationRaw[key]["time"] = currTimestamp; + + this.aggregatedOutput[locationKey].precipationProb[key]["val"] = probability; // probability of open weather + this.aggregatedOutput[locationKey].precipationProb[key]["time"] = currTimestamp; + + } + + //remove dead info + if(Object.keys(this.aggregatedOutput[locationKey].precipationRaw[key]).length == 0 ){ + delete this.aggregatedOutput[locationKey].precipationRaw[key]; + }; + + if(Object.keys(this.aggregatedOutput[locationKey].precipationProb[key]).length == 0 ){ + delete this.aggregatedOutput[locationKey].precipationProb[key]; + }; + + }); + }); + + //total sum expected over time window (just for ref now not so important anymore) + this.sumRain = Object.values(totalProb).reduce((sum, value) => sum + value, 0); + this.avgRain = this.sumRain / numberOfLocations; + + //make average over prob + Object.entries(totalProb).forEach(([key, sum],index) => { + typeof totalAvg[key] === 'undefined' ? totalAvg[key] = 0 : null; + totalAvg[key] = sum / numberOfLocations; + }); + + //make new prediction + //this.get_model_prediction(); + return this.aggregatedOutput; + } + + // for getting the day of the year (0-365) + getDayOfYear(ts){ + const start = new Date(ts.getFullYear(), 0, 1); + const diff = ts - start; + const oneDay = 1000 * 60 * 60 * 24; + return Math.floor(diff / oneDay); +} + +// for 'zipping' data into the right shape for the model +zip(...arrays) { + return arrays[0].map((_, i) => arrays.map(arr => arr[i])); +} + + get_model_prediction(){ + +// combine 24 hourly predictions to make one daily prediction (for the next 24 hours including the current hour) +let inputs = []; +for (let predHour = 0; predHour <= 23; predHour++) { + + // select 48 timestamps based on hour te be predicted + let now = new Date(); + const lastHour = new Date(now.setHours(now.getHours() + predHour)); + let timestamps = this.rain_data[0].hourly.time.map(ts => new Date(ts)); + let timestamps_48 = timestamps.filter(ts => ts <= lastHour).slice(-48) + + // for each relevant hour calculate the mean precipitation across all areas +let precipitation = []; +for (let i = 0; i < timestamps.length; i++) { + + if(timestamps_48.includes(timestamps[i])) { + + let values = []; + for (let j = 0; j < this.rain_data.length; j++) { + + values.push(this.rain_data[j].hourly.precipitation[i]); + } + let mean = values.reduce((sum, value) => sum + value, 0) / this.rain_data.length; + precipitation.push(mean); + } + } + + // generate seasonal variables for model: hour of day, day of week, day of year (last 2 with sin cos transformation) + const hour = timestamps_48.map(ts => ts.getHours()); + const weekdayJS = timestamps_48.map(ts => ts.getDay()); // Javascript weekday + const weekdayPY = weekdayJS.map(weekdayJS => (weekdayJS + 6) % 7); // Python weekday + const weekdaySin = weekdayPY.map(weekdayPY => Math.sin(2 * Math.PI * weekdayPY / 7)); + const weekdayCos = weekdayPY.map(weekdayPY => Math.cos(2 * Math.PI * weekdayPY / 7)); + const dayOfYear = timestamps_48.map(ts => getDayOfYear(ts)); + const dayOfYearSin = dayOfYear.map(day => Math.sin(2 * Math.PI * day / 365)); + const dayOfYearCos = dayOfYear.map(day => Math.cos(2 * Math.PI * day / 365)); + + // standardize variables for prediction and 'zip' them + const scaling = [ + { + "hour mean": 11.504046716524947, + "weekdaySin mean": -0.00023422353487966347, + "weekdayCos mean": 0.0033714029956787715, + "dayOfYearSin mean": 0.06748893577363864, + "dayOfYearCos mean": -0.02137433139416939, + "precipitation mean": 0.0887225073082283 + }, + { + "hour scale": 6.92182769305216, + "weekdaySin scale": 0.7073194528907719, + "weekdayCos scale": 0.7068859670013796, + "dayOfYearSin scale": 0.701099604274817, + "dayOfYearCos scale": 0.7095405037003095, + "precipitation scale": 0.4505403578968155 + }, + { + "Flow (m3/h) mean": 1178.7800890533754 + }, + { + "Flow (m3/h) scale": 1025.3973622173557 + } +] +const means = scaling[0]; +const scales = scaling[1]; + +let features = [hour, weekdaySin, weekdayCos, dayOfYearSin, dayOfYearCos, precipitation]; +const names = ["hour", "weekdaySin", "weekdayCos", "dayOfYearSin", "dayOfYearCos", "precipitation"] + +features = features.map((arr, i) => + arr.map(value => (value - means[`${names[i]} mean`]) / scales[`${names[i]} scale`])); +[hour, weekdaySin, weekdayCos, dayOfYearSin, dayOfYearCos, precipitation] = features; + + const zipped = zip(hour, weekdaySin, weekdayCos, dayOfYearSin, dayOfYearCos, precipitation); + + // collect inputdata for model + inputs.push(zipped); +} + const output = this.model_loader(inputs); + console.log('Final output: ' + output); + } + +async model_loader(inputs){ + + let dailyPred = 0; + + try { + const localURL = "http://127.0.0.1:1880/generalFunctions/datasets/lstmData/tfjs_model/model.json"; + + // Could you log the original model JSON to help determine the correct input shape? + const response = await fetch(localURL); + const modelJSON = await response.json(); + console.log('Original model config:', JSON.stringify(modelJSON.modelTopology.model_config.config.layers[0], null, 48, 6)); + + // Try loading with default input shape + const model = await this.modelLoader.loadModel(localURL); + console.log('Model loaded successfully!'); + + // make predictions + for (const input of inputs) { + + const inputTensor = tf.tensor3d([input]); + const predict = model.predict(inputTensor); + let predictValue = await predict.data(); + + // back-transformation because of standardization of the response variable + predictValue = predictValue[0] * 1024.1940942 + 1188.0105115; + dailyPred += predictValue; + } + console.log('Daily prediction: ' + dailyPred); + } catch (error) { + console.error('Failed to load model:', error); + } + return dailyPred; +} + + sampling_program(){ + + // ------------------ Run once on conditions and start sampling + if( ( (this.i_start ) || ( Date.now() >= this.nextDate ) ) && !this.running ){ + + this.running = true; + + // reset persistent vars + this.temp_pulse = 0; + this.pulse = false; + this.bucketVol = 0; + this.sumPuls = 0; + this.m3Total = 0; + this.timePassed = 0; // time in seconds + this.timeLeft = 0; // time in seconds + this.predM3PerSec = 0; + + //run prediction to ensure its value is filled + this.get_model_prediction(); + + // define m3 per pulse for this run and round to int ! + this.m3PerPuls = Math.round(this.predFlow / this.targetPuls); + this.predM3PerSec = this.predFlow / this.sampling_time / 60 / 60; // predicted m3 per time + + // define start and stop time based on calender data + this.start_time = Date.now(); + this.stop_time = Date.now() + (this.sampling_time * 60 * 60 * 1000); // convert to milliseconds + + //reset parameters and look for next date + this.regNextDate(this.monsternametijden); + + // reset start + this.i_start = false; + } + + // ------------------ Run for as long as sampling time is not greater than stop time + if(this.stop_time > Date.now()){ + + // define time vars + this.timePassed = Math.round( ( Date.now() - this.start_time ) / 1000); + this.timeLeft = Math.round( ( this.stop_time - Date.now() ) / 1000); + + // calc temp pulse rate + let update = this.m3PerTick / this.m3PerPuls; + + // update values + this.temp_pulse += update; + this.m3Total += this.m3PerTick; + + // check if we need to send out a pulse (stop sending pulses if capacity is reached) + if(this.temp_pulse >= 1 && this.sumPuls < this.absMaxPuls){ + // reset + this.temp_pulse += -1; + // send out a pulse and add to count + this.pulse = true; + // count pulses + this.sumPuls++; + // update bucket volume each puls + this.bucketVol = Math.round(this.sumPuls * this.volume_pulse * 100) / 100; + + } + else{ + + if( this.sumPuls > this.absMaxPuls){ + + // find out how to reschedule sample automatically? + } + + //update pulse when its true + if(this.pulse){ + this.pulse = false; // continue but don't send out a pulse + } + + } + } + else + { + //after setting once dont do it again + if(this.running){ + // Vars can only be 0 if this is not running + this.m3PerPuls = 0; + this.temp_pulse = 0; + this.pulse = false; + this.bucketVol = 0; + this.sumPuls = 0; + this.timePassed = 0; // time in seconds + this.timeLeft = 0; // time in seconds + this.predFlow = 0; + this.predM3PerSec = 0; + this.m3Total = 0; + this.running = false; // end of sampling program (stop_time reached) + + } + } + } + + flowCalc(){ + //reset timePassed + let timePassed = 0; + + // each tick calc flowtimepassed + this.flowTime > 0 ? timePassed = ( Date.now() - this.flowTime) / 1000 : timePassed = 0 ; + + //conver to m3 per tick + this.m3PerTick = this.q / 60 / 60 * timePassed ; + + // put new timestamp + this.flowTime = Date.now(); + + } + + //goes through time related functions + tick(){ + + //calculate flow based on input + this.flowCalc(); + + //run sampling program + this.sampling_program(); + + //logQ for predictions / forecasts + this.logQoverTime(); + } + + regNextDate(monsternametijden){ + + let next_date = new Date(new Date().setFullYear(new Date().getFullYear() + 1)); + let n_days_remaining = 0; + + if(typeof monsternametijden !== 'undefined'){ + // loop through lines + Object.entries(monsternametijden).forEach(([key, line],index) => { + + //console.log(line.START_DATE); + //check if date is not null + if(line.START_DATE != "NULL"){ + let curr_date_conv = new Date(line.START_DATE); + let curr_date = curr_date_conv.getTime(); + + //check if sample name is this sample and if date is bigger than now. + if(line.SAMPLE_NAME == this.aquonSampleName && curr_date > Date.now() ){ + + //only keep date that is bigger than current but smaller than the ones that follow after it. + if(curr_date < next_date){ next_date = curr_date; } + + // check if its within this year only show those days as days remaining + if( new Date().getFullYear() == curr_date_conv.getFullYear() ){ n_days_remaining++; } + } + } + + }); + } + else{ + //this.warning.push(3); + } + + //store vars remaining + this.daysPerYear = n_days_remaining; + this.nextDate = next_date; + } + + logQoverTime(){ + + //store currHour in temp obj for easy ref + let h = this.currHour; + + // define rain hour of which the correlation is the biggest this doesnt belong in this section do this afterwards + // let rainH = h - this.calcTimeShift ; + + // how much rain fell on rainH (define category) + + // fetch current hour from actual time + const currentHour = new Date().getHours(); + + //on hour change begin log + if(h !== currentHour ){ + + //write current total to object + this.qLineRaw.h = this.tmpTotQ + + //reset tmpTotQ + + //set this.currHour to currentHour + } + + + + + + + } + + //create objects where to push arrays in to keep track of data + createMinMaxSeen(){ + //check which hour it is , then make sum , after sum is complete check which hour it is + //loop over sampling time expressed in hours + for(let h = 1; h < this.sampling_time ; h++){ + this.minSeen = {}; + } + } + + +} // end of class + +module.exports = Monster; + + +const mConfig={ + general: { + name: "Monster", + logging:{ + logLevel: "debug", + enabled: true, + }, + }, + asset: { + emptyWeightBucket: 3, + }, + constraints: { + minVolume: 4, + maxWeight: 23, + }, +} + + +// testing +let monster = new Monster(mConfig); +monster.rain_data = [{"latitude":51.7,"longitude":4.8139997,"generationtime_ms":0.03802776336669922,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.736,"longitude":4.785,"generationtime_ms":0.031948089599609375,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":2,"location_id":1,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.718,"longitude":4.843,"generationtime_ms":0.025987625122070312,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":2,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.718,"longitude":4.8719997,"generationtime_ms":0.054001808166503906,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":4,"location_id":3,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.718,"longitude":4.93,"generationtime_ms":0.03802776336669922,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":4,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.718,"longitude":4.9589996,"generationtime_ms":0.03504753112792969,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":5,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.718,"longitude":4.988,"generationtime_ms":0.027060508728027344,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":6,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.7,"longitude":4.785,"generationtime_ms":0.033974647521972656,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":7,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.7,"longitude":4.8139997,"generationtime_ms":0.05602836608886719,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":8,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.7,"longitude":4.843,"generationtime_ms":0.029921531677246094,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":9,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.7,"longitude":4.8719997,"generationtime_ms":0.033020973205566406,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":3,"location_id":10,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.7,"longitude":4.93,"generationtime_ms":0.054955482482910156,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":11,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.785,"generationtime_ms":0.04506111145019531,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":12,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.8139997,"generationtime_ms":0.031948089599609375,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":13,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.843,"generationtime_ms":0.02002716064453125,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":4,"location_id":14,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.8719997,"generationtime_ms":0.04398822784423828,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":15,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.93,"generationtime_ms":0.05602836608886719,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":-1,"location_id":16,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.664,"longitude":4.9589996,"generationtime_ms":0.030040740966796875,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":17,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.785,"generationtime_ms":0.02300739288330078,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":0,"location_id":18,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.8139997,"generationtime_ms":0.04100799560546875,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":3,"location_id":19,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.843,"generationtime_ms":0.04494190216064453,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":5,"location_id":20,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.8719997,"generationtime_ms":0.03898143768310547,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":3,"location_id":21,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.93,"generationtime_ms":0.030040740966796875,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":3,"location_id":22,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.646,"longitude":4.9589996,"generationtime_ms":0.07402896881103516,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":1,"location_id":23,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.628,"longitude":4.8139997,"generationtime_ms":0.024080276489257812,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":3,"location_id":24,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.628,"longitude":4.843,"generationtime_ms":0.0209808349609375,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":17,"location_id":25,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.628,"longitude":4.8719997,"generationtime_ms":0.04398822784423828,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":7,"location_id":26,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.628,"longitude":4.93,"generationtime_ms":0.033974647521972656,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":5,"location_id":27,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.592,"longitude":4.8719997,"generationtime_ms":0.02300739288330078,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":14,"location_id":28,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},{"latitude":51.592,"longitude":4.93,"generationtime_ms":0.0209808349609375,"utc_offset_seconds":3600,"timezone":"Europe/Berlin","timezone_abbreviation":"CET","elevation":6,"location_id":29,"hourly_units":{"time":"iso8601","precipitation":"mm","precipitation_probability":"%"},"hourly":{"time":["2024-11-04T00:00","2024-11-04T01:00","2024-11-04T02:00","2024-11-04T03:00","2024-11-04T04:00","2024-11-04T05:00","2024-11-04T06:00","2024-11-04T07:00","2024-11-04T08:00","2024-11-04T09:00","2024-11-04T10:00","2024-11-04T11:00","2024-11-04T12:00","2024-11-04T13:00","2024-11-04T14:00","2024-11-04T15:00","2024-11-04T16:00","2024-11-04T17:00","2024-11-04T18:00","2024-11-04T19:00","2024-11-04T20:00","2024-11-04T21:00","2024-11-04T22:00","2024-11-04T23:00","2024-11-05T00:00","2024-11-05T01:00","2024-11-05T02:00","2024-11-05T03:00","2024-11-05T04:00","2024-11-05T05:00","2024-11-05T06:00","2024-11-05T07:00","2024-11-05T08:00","2024-11-05T09:00","2024-11-05T10:00","2024-11-05T11:00","2024-11-05T12:00","2024-11-05T13:00","2024-11-05T14:00","2024-11-05T15:00","2024-11-05T16:00","2024-11-05T17:00","2024-11-05T18:00","2024-11-05T19:00","2024-11-05T20:00","2024-11-05T21:00","2024-11-05T22:00","2024-11-05T23:00","2024-11-06T00:00","2024-11-06T01:00","2024-11-06T02:00","2024-11-06T03:00","2024-11-06T04:00","2024-11-06T05:00","2024-11-06T06:00","2024-11-06T07:00","2024-11-06T08:00","2024-11-06T09:00","2024-11-06T10:00","2024-11-06T11:00","2024-11-06T12:00","2024-11-06T13:00","2024-11-06T14:00","2024-11-06T15:00","2024-11-06T16:00","2024-11-06T17:00","2024-11-06T18:00","2024-11-06T19:00","2024-11-06T20:00","2024-11-06T21:00","2024-11-06T22:00","2024-11-06T23:00","2024-11-07T00:00","2024-11-07T01:00","2024-11-07T02:00","2024-11-07T03:00","2024-11-07T04:00","2024-11-07T05:00","2024-11-07T06:00","2024-11-07T07:00","2024-11-07T08:00","2024-11-07T09:00","2024-11-07T10:00","2024-11-07T11:00","2024-11-07T12:00","2024-11-07T13:00","2024-11-07T14:00","2024-11-07T15:00","2024-11-07T16:00","2024-11-07T17:00","2024-11-07T18:00","2024-11-07T19:00","2024-11-07T20:00","2024-11-07T21:00","2024-11-07T22:00","2024-11-07T23:00"],"precipitation":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"precipitation_probability":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}}] + + diff --git a/dependencies/monster/monster_class.js b/dependencies/monster/monster_class_oud.js similarity index 100% rename from dependencies/monster/monster_class.js rename to dependencies/monster/monster_class_oud.js diff --git a/monster oud.js b/monster oud.js new file mode 100644 index 0000000..f4e0501 --- /dev/null +++ b/monster oud.js @@ -0,0 +1,182 @@ +module.exports = function (RED) { + function monster(config) { + + // create node + RED.nodes.createNode(this, config); + + // call this => node so whenver you want to call a node function type node and the function behind it + var node = this; + + try{ + + + // fetch monster object from monster.js + const Monster = require("./dependencies/monster/monster_class"); + const OutputUtils = require("../generalFunctions/helper/outputUtils"); + + const mConfig={ + general: { + name: config.name, + id: node.id, + unit: config.unit, + logging:{ + logLevel: config.logLevel, + enabled: config.enableLog, + }, + }, + asset: { + supplier: config.supplier, + subType: config.subType, + model: config.model, + emptyWeightBucket: config.emptyWeightBucket, + }, + constraints: { + minVolume: config.minVolume, + maxWeight: config.maxWeight, + samplingtime: config.samplingtime, + }, + } + + // make new monster on creation to work with. + const m = new Monster(mConfig); + + // put m on node memory as source + node.source = m; + + //load output utils + const output = new OutputUtils(); + + //internal vars + this.interval_id = null; + + //updating node state + function updateNodeStatus() { + try{ + + const bucketVol = m.bucketVol; + const maxVolume = m.maxVolume; + const state = m.running; + const mode = "AI" ; //m.mode; + + let status; + + switch (state) { + case false: + status = { fill: "red", shape: "dot", text: `${mode}: OFF` }; + break; + case true: + status = { fill: "green", shape: "dot", text: `${mode}: ON => ${bucketVol} | ${maxVolume}` }; + break; + } + + return status; + } catch (error) { + node.error("Error in updateNodeStatus: " + error); + return { fill: "red", shape: "ring", text: "Status Error" }; + } + } + + function tick(){ + try{ + // load status node + const status = updateNodeStatus(); + // kick time based function in node + m.tick(); + //show node status + node.status(status); + } catch (error) { + node.error("Error in tick function: " + error); + node.status({ fill: "red", shape: "ring", text: "Tick Error" }); + } + } + + // register child on first output this timeout is needed because of node - red stuff + setTimeout( + () => { + + /*---execute code on first start----*/ + let msgs = []; + + msgs[2] = { topic : "registerChild" , payload: node.id, positionVsParent: "upstream" }; + msgs[3] = { topic : "registerChild" , payload: node.id, positionVsParent: "downstream" }; + + //send msg + this.send(msgs); + }, + 100 + ); + + //declare refresh interval internal node + setTimeout( + () => { + /*---execute code on first start----*/ + this.interval_id = setInterval(function(){ tick() },1000) + }, + 1000 + ); + + node.on('input', function (msg,send,done) { + try{ + switch(msg.topic) { + case 'registerChild': + const childId = msg.payload; + const childObj = RED.nodes.getNode(childId); + m.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent); + break; + case 'setMode': + m.setMode(msg.payload); + break; + case 'start': + m.i_start = true; + break; + } + } catch (error) { + node.error("Error in input function: " + error); + node.status({ fill: "red", shape: "ring", text: "Input Error" }); + } + + if(msg.topic == "i_flow"){ + monster.q = parseFloat(msg.payload); + } + + if(msg.topic == "i_start"){ + monster.i_start = true; + } + + if(msg.topic == "model_prediction"){ + let var1 = msg.payload.dagvoorheen; + let var2 = msg.payload.dagnadien; + monster.get_model_prediction(var1, var2); + } + + if(msg.topic == "aquon_monsternametijden"){ + monster.monsternametijden = msg.payload; + } + + if(msg.topic == "rain_data"){ + monster.rain_data = msg.payload; + } + + //register child classes + if(msg.topic == "registerChild"){ + let child = msg.payload; + monster.registerChild(child); + + } + + done(); + }); + + // tidy up any async code here - shutdown connections and so on. + node.on('close', function() { + clearTimeout(this.interval_id); + }); + + } catch (error) { + node.error("Error in monster function: " + error); + node.status({ fill: "red", shape: "ring", text: "Monster Error" }); + } + } + RED.nodes.registerType("monster", monster); + +}; \ No newline at end of file diff --git a/monster.html b/monster.html index 12d421f..90e425e 100644 --- a/monster.html +++ b/monster.html @@ -1,269 +1,143 @@ - + -RED.nodes.registerType('monster', { - - category: 'wbd typical', - color: '#4f8582', - - defaults: { + - + +

Monster node: Configure a monster asset.

+ + \ No newline at end of file diff --git a/monster.js b/monster.js index f4e0501..3850feb 100644 --- a/monster.js +++ b/monster.js @@ -1,182 +1,35 @@ -module.exports = function (RED) { - function monster(config) { +const nameOfNode = 'monster'; +const nodeClass = require('./src/nodeClass.js'); +const { MenuManager, configManager } = require('generalFunctions'); - // create node +module.exports = function(RED) { + // 1) Register the node type and delegate to your class + RED.nodes.registerType(nameOfNode, function(config) { RED.nodes.createNode(this, config); + this.nodeClass = new nodeClass(config, RED, this, nameOfNode); + }); - // call this => node so whenver you want to call a node function type node and the function behind it - var node = this; + // 2) Setup the dynamic menu & config endpoints + const menuMgr = new MenuManager(); + const cfgMgr = new configManager(); - try{ - - - // fetch monster object from monster.js - const Monster = require("./dependencies/monster/monster_class"); - const OutputUtils = require("../generalFunctions/helper/outputUtils"); - - const mConfig={ - general: { - name: config.name, - id: node.id, - unit: config.unit, - logging:{ - logLevel: config.logLevel, - enabled: config.enableLog, - }, - }, - asset: { - supplier: config.supplier, - subType: config.subType, - model: config.model, - emptyWeightBucket: config.emptyWeightBucket, - }, - constraints: { - minVolume: config.minVolume, - maxWeight: config.maxWeight, - samplingtime: config.samplingtime, - }, + // Serve /monster/menu.js + RED.httpAdmin.get(`/${nameOfNode}/menu.js`, (req, res) => { + try { + const script = menuMgr.createEndpoint(nameOfNode, ['logger','position']); + res.type('application/javascript').send(script); + } catch (err) { + res.status(500).send(`// Error generating menu: ${err.message}`); } + }); - // make new monster on creation to work with. - const m = new Monster(mConfig); - - // put m on node memory as source - node.source = m; - - //load output utils - const output = new OutputUtils(); - - //internal vars - this.interval_id = null; - - //updating node state - function updateNodeStatus() { - try{ - - const bucketVol = m.bucketVol; - const maxVolume = m.maxVolume; - const state = m.running; - const mode = "AI" ; //m.mode; - - let status; - - switch (state) { - case false: - status = { fill: "red", shape: "dot", text: `${mode}: OFF` }; - break; - case true: - status = { fill: "green", shape: "dot", text: `${mode}: ON => ${bucketVol} | ${maxVolume}` }; - break; - } - - return status; - } catch (error) { - node.error("Error in updateNodeStatus: " + error); - return { fill: "red", shape: "ring", text: "Status Error" }; - } + // Serve /monster/configData.js + RED.httpAdmin.get(`/${nameOfNode}/configData.js`, (req, res) => { + try { + const script = cfgMgr.createEndpoint(nameOfNode); + res.type('application/javascript').send(script); + } catch (err) { + res.status(500).send(`// Error generating configData: ${err.message}`); } - - function tick(){ - try{ - // load status node - const status = updateNodeStatus(); - // kick time based function in node - m.tick(); - //show node status - node.status(status); - } catch (error) { - node.error("Error in tick function: " + error); - node.status({ fill: "red", shape: "ring", text: "Tick Error" }); - } - } - - // register child on first output this timeout is needed because of node - red stuff - setTimeout( - () => { - - /*---execute code on first start----*/ - let msgs = []; - - msgs[2] = { topic : "registerChild" , payload: node.id, positionVsParent: "upstream" }; - msgs[3] = { topic : "registerChild" , payload: node.id, positionVsParent: "downstream" }; - - //send msg - this.send(msgs); - }, - 100 - ); - - //declare refresh interval internal node - setTimeout( - () => { - /*---execute code on first start----*/ - this.interval_id = setInterval(function(){ tick() },1000) - }, - 1000 - ); - - node.on('input', function (msg,send,done) { - try{ - switch(msg.topic) { - case 'registerChild': - const childId = msg.payload; - const childObj = RED.nodes.getNode(childId); - m.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent); - break; - case 'setMode': - m.setMode(msg.payload); - break; - case 'start': - m.i_start = true; - break; - } - } catch (error) { - node.error("Error in input function: " + error); - node.status({ fill: "red", shape: "ring", text: "Input Error" }); - } - - if(msg.topic == "i_flow"){ - monster.q = parseFloat(msg.payload); - } - - if(msg.topic == "i_start"){ - monster.i_start = true; - } - - if(msg.topic == "model_prediction"){ - let var1 = msg.payload.dagvoorheen; - let var2 = msg.payload.dagnadien; - monster.get_model_prediction(var1, var2); - } - - if(msg.topic == "aquon_monsternametijden"){ - monster.monsternametijden = msg.payload; - } - - if(msg.topic == "rain_data"){ - monster.rain_data = msg.payload; - } - - //register child classes - if(msg.topic == "registerChild"){ - let child = msg.payload; - monster.registerChild(child); - - } - - done(); - }); - - // tidy up any async code here - shutdown connections and so on. - node.on('close', function() { - clearTimeout(this.interval_id); - }); - - } catch (error) { - node.error("Error in monster function: " + error); - node.status({ fill: "red", shape: "ring", text: "Monster Error" }); - } - } - RED.nodes.registerType("monster", monster); - + }); }; \ No newline at end of file diff --git a/src/nodeClass.js b/src/nodeClass.js new file mode 100644 index 0000000..a72ca9c --- /dev/null +++ b/src/nodeClass.js @@ -0,0 +1,220 @@ +/** + * node class.js + * + * Encapsulates all node logic in a reusable class. In future updates we can split this into multiple generic classes and use the config to specifiy which ones to use. + * This allows us to keep the Node-RED node clean and focused on wiring up the UI and event handlers. + */ +const { outputUtils, configManager } = require('generalFunctions'); +const Specific = require("./specificClass"); + +class nodeClass { + /** + * Create a Node. + * @param {object} uiConfig - Node-RED node configuration. + * @param {object} RED - Node-RED runtime API. + */ + constructor(uiConfig, RED, nodeInstance, nameOfNode) { + + // Preserve RED reference for HTTP endpoints if needed + this.node = nodeInstance; // This is the Node-RED node instance, we can use this to send messages and update status + this.RED = RED; // This is the Node-RED runtime API, we can use this to create endpoints if needed + this.name = nameOfNode; // This is the name of the node, it should match the file name and the node type in Node-RED + this.source = null; // Will hold the specific class instance + this.config = null; // Will hold the merged configuration + + // Load default & UI config + this._loadConfig(uiConfig,this.node); + + // Instantiate core class + this._setupSpecificClass(uiConfig); + + // Wire up event and lifecycle handlers + this._bindEvents(); + this._registerChild(); + this._startTickLoop(); + this._attachInputHandler(); + this._attachCloseHandler(); + } + + /** + * Load and merge default config with user-defined settings. + * @param {object} uiConfig - Raw config from Node-RED UI. + */ + _loadConfig(uiConfig,node) { + + // Merge UI config over defaults + this.config = { + general: { + id: node.id, // node.id is for the child registration process + unit: uiConfig.unit, // add converter options later to convert to default units (need like a model that defines this which units we are going to use and then conver to those standards) + logging: { + enabled: uiConfig.enableLog, + logLevel: uiConfig.logLevel + } + }, + asset: { + uuid: uiConfig.assetUuid, //need to add this later to the asset model + tagCode: uiConfig.assetTagCode, //need to add this later to the asset model + supplier: uiConfig.supplier, + category: uiConfig.category, //add later to define as the software type + type: uiConfig.assetType, + model: uiConfig.model, + unit: uiConfig.unit + }, + functionality: { + positionVsParent: uiConfig.positionVsParent + } + }; + + // Utility for formatting outputs + this._output = new outputUtils(); + } + + /** + * Instantiate the core Measurement logic and store as source. + */ + _setupSpecificClass(uiConfig) { + const monsterConfig = this.config; + + this.source = new Specific(monsterConfig); + + //store in node + this.node.source = this.source; // Store the source in the node instance for easy access + + } + + /** + * Bind events to Node-RED status updates. Using internal emitter. --> REMOVE LATER WE NEED ONLY COMPLETE CHILDS AND THEN CHECK FOR UPDATES + */ + _bindEvents() { + + } + + _updateNodeStatus() { + const m = this.source; +try{ + const bucketVol = m.bucketVol; + const maxVolume = m.maxVolume; + const state = m.running; + const mode = "AI" ; //m.mode; + + let status; + + switch (state) { + case false: + status = { fill: "red", shape: "dot", text: `${mode}: OFF` }; + break; + case true: + status = { fill: "green", shape: "dot", text: `${mode}: ON => ${bucketVol} | ${maxVolume}` }; + break; + } + + return status; + } catch (error) { + node.error("Error in updateNodeStatus: " + error); + return { fill: "red", shape: "ring", text: "Status Error" }; + } + } + /** + * Register this node as a child upstream and downstream. + * Delayed to avoid Node-RED startup race conditions. + */ + _registerChild() { + setTimeout(() => { + this.node.send([ + null, + null, + { topic: 'registerChild', payload: this.config.general.id, positionVsParent: this.config?.functionality?.positionVsParent || 'atEquipment' }, + ]); + }, 100); + } + + /** + * Start the periodic tick loop. + */ + _startTickLoop() { + setTimeout(() => { + this._tickInterval = setInterval(() => this._tick(), 1000); + + // Update node status on nodered screen every second ( this is not the best way to do this, but it works for now) + this._statusInterval = setInterval(() => { + const status = this._updateNodeStatus(); + this.node.status(status); + }, 1000); + + }, 1000); + } + + /** + * Execute a single tick: update measurement, format and send outputs. + */ + _tick() { + this.source.tick(); + + const raw = this.source.getOutput(); + const processMsg = this._output.formatMsg(raw, this.config, 'process'); + const influxMsg = this._output.formatMsg(raw, this.config, 'influxdb'); + + // Send only updated outputs on ports 0 & 1 + this.node.send([processMsg, influxMsg]); + } + + /** + * Attach the node's input handler, routing control messages to the class. + */ + _attachInputHandler() { + this.node.on('input', (msg, send, done) => { + /* Update to complete event based node by putting the tick function after an input event */ + const m = this.source; + switch(msg.topic) { + case 'registerChild': + // Register this node as a child of the parent node + const childId = msg.payload; + const childObj = this.RED.nodes.getNode(childId); + m.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent); + break; + case 'setMode': + m.setMode(msg.payload); + break; + case 'execSequence': + const { source, action, parameter } = msg.payload; + m.handleInput(source, action, parameter); + break; + case 'execMovement': + const { source: mvSource, action: mvAction, setpoint } = msg.payload; + m.handleInput(mvSource, mvAction, Number(setpoint)); + break; + case 'flowMovement': + const { source: fmSource, action: fmAction, setpoint: fmSetpoint } = msg.payload; + m.handleInput(fmSource, fmAction, Number(fmSetpoint)); + + break; + case 'emergencystop': + const { source: esSource, action: esAction } = msg.payload; + m.handleInput(esSource, esAction); + break; + case 'showWorkingCurves': + m.showWorkingCurves(); + send({ topic : "Showing curve" , payload: m.showWorkingCurves() }); + break; + case 'CoG': + m.showCoG(); + send({ topic : "Showing CoG" , payload: m.showCoG() }); + break; + } + }); + } + + /** + * Clean up timers and intervals when Node-RED stops the node. + */ + _attachCloseHandler() { + this.node.on('close', (done) => { + clearInterval(this._tickInterval); + clearInterval(this._statusInterval); + done(); + }); + } +} + +module.exports = nodeClass;