Shower script

I am trying to make a script which can detect when some one takes a shower. The way i try to do this is is with the data from my Smartgate watermeter. This is my initial script.

const date = new Date();
const currentYear = date.getFullYear();
const currentMonth = date.getMonth() + 1;
const currentDay = new Date().getDate();
var minutes = date.getMinutes();
var hours = date.getHours();
var totalMinutes = (60 * hours) + minutes;
console.log('totalMinutes is:'+totalMinutes);

waterMeterShowerUpdate = global.get('waterMeterShowerUpdate');
console.log('waterMeterShowerUpdate is: ' +waterMeterShowerUpdate)
if(waterMeterShowerUpdate === false)
{
global.set('waterMeterShowerUpdate', true);
var waterMeterShower = Array(1440).fill(0);
global.set('waterMeterShower', waterMeterShower )
}
var waterMeterShower = global.get('waterMeterShower');
waterMeter = global.get('waterMeterDay'+currentYear +currentMonth);
var tmpWaterMeter = waterMeter[currentDay -1];
waterMeterShower.splice(totalMinutes,1,tmpWaterMeter);
global.set('waterMeterShower', waterMeterShower);

The global variable “waterMeterShower” has a length of 1440 . This is equal to all minutes in one day. With some advanced flows the array will only get new data when the watermeter is running. This way i don’t have to make a flow which runs every minute. I hope the array will look something like this [0,0,0,0,3855,0,3857,0,0,0,3859,3864,3868,3875,3879,3884,3890,3900,0,0,0,0,0,0,0,0]. Because every index number is the equivalent of a minute i want to detect the series of multiple numbers > 0 in a row. So the serie 3859,3864,3868,3875,3879,3884,3890,3900, has 8 entries, 8 entries is 8 minutes, so the water has been running for 8 minutes. In my householding this will be most of the time the shower. But the duration could also be 5 minutes or 17 minutes(my son) How do i find these kind of series? I want to save these series in variables or new arrays. From that point of i want to substract the last entry of a serie(3900) from the first entry of this serie(3859). This way i know 41 liters were used during 8 minutes. The array will be renewed everyday.

let arr = [0,0,0,0,3855,0,3857,0,0,0,3859,3864,3868,3875,3879,3884,3890,3900,0,0,0,0,0,0,0,0];

let objs = _.map(arr, a=>{return {amount:a}; });
_.each(objs, (x,index)=> { 
  if(x.amount===0) return;// x.time=-1;
  let yi = _.findIndex(objs, (y,yIndex)=>yIndex>index && y.amount==0)
  x.time = yi-index;

  })

console.log(objs)
console.log('Total used: ' + (_.findLast(objs,x=>x.amount!=0).amount - _.find(objs,x=>x.amount!=0).amount));
1 Like

One question(noob), i get the results as objects. But don’t how to search these objects. I want to search for those objects that have more than four minutes. In that case i want the entire objects until the next zero. When there are more objects with also a serie more than four minutes, i want that serie also. Maybe a search for those series and saving in a array. Is that possible?

Like this?

let arr = [0,0,0,0,3855,0,3857,0,0,0,3859,3864,3868,3875,3879,3884,3890,3900,0,0,0,0,0,0,0,0];
let time = 4;


let objs = _.map(arr, a=>{return {amount:a}; });
_.each(objs, (x,index)=> { 
  if(x.amount===0) return;// x.time=-1;
  let yi = _.findIndex(objs, (y,yIndex)=>yIndex>index && y.amount==0)
  x.time = yi-index;

  })

console.log(objs)
console.log('Total used: ' + (_.findLast(objs,x=>x.amount!=0).amount - _.find(objs,x=>x.amount!=0).amount));

let ret = _.filter(objs, x=>x.time>= time );
ret = _.map(ret, x=> { return x.amount; } );
console.log(ret);

Output of the last console.log:

[ 3859, 3864, 3868, 3875, 3879 ]

Yes, that is goiing the right way. I myself tried it with this, and that gives kind of how i am thinking. The problem with my script is it stopped after the first serie. I tried to make a function of it, but in that case i need to know how many series i would get, which will be different every day. So i am stuck at the moment. This is the script i made yesterday evening

let indices = [0,0,0,0,3855,0,3857,0,0,0,3859,3864,3868,3875,3879,3884,3890,3900,0,0,0,0,0,0,0,0,3910,1915,1917,3919,3925,3929,0,0,0,0,0,3934,3939,3944,3949,3955,3970,0,0,0,0,0,0];

var count = 0;

function searchShowerEvents()
{
while((count +1) <= indices.length)
{
if(indices[count] > 0 && indices[count +1] > 0 && indices[count +2] > 0 && indices[count +3] && indices[count +4] > 0 )
{
var firstIndex = indices.indexOf(indices[count]);
global.set('firstIndex', firstIndex)
console.log('firstIndex is: '+firstIndex)
console.log('Index is: ' +indices[count] +' en ' +(indices[count +1]))
break;
}
count++
}
console.log('count is: '+count)
}

function searchIndex()
{
var teller = count
while(teller <= indices.length)
{
if(indices[teller] === 0)
{
var lastIndex = (indices.indexOf(indices[teller -1])) + 1;
console.log('lastIndex is: '+lastIndex);
var firstIndex = global.get('firstIndex');
console.log('firstIndex is: '+firstIndex)
var totalWater = (indices[lastIndex -1] - indices[firstIndex]) ;
console.log('totalWater is: '+totalWater);
break;
}
teller++
}
console.log('index start is ' +firstIndex +' en index einde is: '+lastIndex)
var minutes = lastIndex - firstIndex
console.log('Douchbeurt duurde '+minutes +' minuten' +' en er werd '+totalWater +' liter water verbruikt')
global.set('teller', teller)
}

searchShowerEvents();
searchIndex()

var teller = global.get('teller')
if(teller <= indices.length)
{
count = teller
searchShowerEvents();
searchIndex()
}

Please Explain, perhaps in Dutch if thats easier, what it is you want?
Why do you need to know how many series there are?

I can make a function, sure, but, what do you want out of it?
The indices array as input, shower-length/time as argument and my array as output?

Wat ik graag wil is dat er gezocht wordt naar series van aaneengesloten cijfers boven de nul, waarbij de serie minimaal 4 indexes lang is. Als er een serie is van 4 aaneengesloten indexes waarbij het getal boven de nul uitkomt dan moet de gehele serie aaneengesloten indexes naar een array worden gekopieerd naar index 0. Daarna moet de zoekfunctie verder gaan zoeken vanaf de laatste index van deze gekopieerd serie. De volgende serie van vier aaneengesloten indexes moet dan worden gezocht en ook hier dan weer de gehele serie van aaneengesloten indexes kopieren naar die array naar index 1 etc etc

De tijd is niet belangrijk omdat een index van 5 cijfers gelijk staat aan 5 minuten, dat kan ik er zelf dus wel uithalen.

Alright, this might be more like it than.

You can get a double-array or a flat array, whatever you like.

let arr = [0,0,0,0,3855,0,3857,0,0,0,3859,3860,3861,3862,3863,3864, 0,3868,0,3875,3876,3877,3878,3879,0,3884,3885,3886,3887,3888,3889,3890,0,3900,0,0,0,0,0,0,0,0];
let time =4;


// Here we go, non-flat, or, double array
let ret = getShowerArray(arr, time, false);
console.log(ret);
// And flat array
let retFlat = getShowerArray(arr, time, true);
console.log(retFlat);




function getShowerArray (indices, showerTime, asFlatArray) {

  let objs = _.map(indices, a=>{return {amount:a}; });
  _.each(objs, (x,index)=> { 
    if(x.amount===0) return;// x.time=-1;
    let yi = _.findIndex(objs, (y,yIndex)=>yIndex>index && y.amount==0)
    x.time = yi-index;
  });

  let output = [], active=false;//, ret2 = _.filter(objs, x=>x.time);
  _.each(objs, (x, index)=> {
    if(!x.time) active=false;  
    else if(active) output[output.length-1].push(x.amount);
    else if(x.time>=showerTime) {
      output.push([x.amount]);
      active = true;
    }
  });
  return asFlatArray ? _.flatMap(output) :output;

}

Output

Double array

[
  [ 3859, 3860, 3861, 3862, 3863, 3864 ],
  [ 3875, 3876, 3877, 3878, 3879 ],
  [ 3884, 3885, 3886, 3887, 3888, 3889, 3890 ]
]

Or flat array

[
  3859, 3860, 3861, 3862, 3863, 3864, 3875, 3876, 3877, 3878, 3879, 3884, 3885, 3886, 3887, 3888, 3889, 3890
]
1 Like

Fastastic, double array was what i was looking for. Now i go further scripting.
Thx a lot, much appreciated

1 Like