Percent Used Bar Chart
-
We have a few MQTT occupancy sensors that have a binary data point called "occupancy" that indicates a cubicle is vacant (0) or occupied (1).
The client would like to trend the utilization of each sensor by hour or day for a certain time range. For example, the client would like to see a bar chart of percent used of a cubicle by hour for Today So Far. Any advise on how to approach this?
BR,
Ricardo -
I can see two ways of doing this, maybe three but am not sure how well maStatistics will work for you.
-
use a meta point to have start (0) and stop (finished time in minutes) then sum the results up into an hourly period with another meta point to derive hourly percentages.
-
do the above with a dedicated component to the same thing with a single pull of all values in a given time frame and calculate it all in one go.
-
possibly use ma statistics to derive mean and average values/times. I do not use this directive as it has no application for me at this time and is a bit resource intensive.
Good luck
Fox
-
-
Like Fox I would use a meta data point, run it every hour. Try this code:
return b.past(HOUR, 1).get(true).percentage;
Check the docs:
-
Thanks Ralf, by the looks of your answer, you'd use percentage, not proportion as per the docs. That or just multiply your answer by 100
Fox
-
A person who never made a mistake never tried anything new. - A.Einstein
Edit and thank you Fox!
-
Thanks for the suggestion. I have implemented a “occupiedTime” meta data point for each occupancy sensor per your suggestion but modifying it so that it captures the hourly occupied time in the hour. However, the client would like to do further analytics by binning the occupied time into 3 groups: <1 min, <10min and >10min. Would you suggest to change the meta data point from update hourly interval to possibly update by context update?
Also any suggestions on how to create a pie chart to present the distribution of the three binned groups?
BR,
Ricardo -
@ricardo said in Percent Used Bar Chart:
Would you suggest to change the meta data point from update hourly interval to possibly update by context update?
No because that means your code would fire and look at the previous hour every time an update came in.
However, the client would like to do further analytics by binning the occupied time into 3 groups: <1 min, <10min and >10min.
Then I advise you look at my initial suggestion as I figured this would happen. You need this to work as occupied events, not just overall statistics. These events can then be evaluated and set a value on a datapoint that represents each timeframe. I'd advise a scripting datasource in this instance as each datapoint mentioned all relates basck to the same script.
Also, please read the docs and give things a go. We're not here to do your job for you.
The StartsAndRuntimeList object is returned by Binary and Multistate points. It contains the following properties: periodStartTime (integer) the start time used for the calculation periodEndTime (integer) the end time used for the calculation --> count (integer) count of the total number of entries startValue: the value before or exactly at the period start time firstValue: the first value in the period firstTime: (integer) the time of the first value lastValue: the last value in the period lastTime: (integer) the time of the last value data: (array) the list of individual StartAndRuntime objects. Each StartAndRuntime object has the following properties: value: (boolean for Binary, integer for Multistate) the point state to which the remaining properties apply starts: (integer) the number of times the state was entered over the period --> runtime: (integer) the amount of time in milliseconds the point was in the state over the period proportion: (float) the proportion of the period the point was in the state (runtime / real duration)
Fox
-
Hi Matt,
Thank you for your follow up. I don't understand which initial suggestion you are referring to, but I have further explored with the idea of using a meta data point for occupiedTime in sec.
The following is the script for the meta data point and it is executed when the occupancy binary (0) is updated (update context checked).
// return o.past(HOUR, 1).get(true).runtime / (60*1000) curState = o.value; lastState = o.lastValue(false).value; if(curState == false) { //falling edge only if(lastState != false) { duration = (o.time - o.lastValue(false).time) / 1000; LOG.info(o.time); LOG.info(o.lastValue(false).time); return duration; }
However, this implementation has a glitch that it generates "zero" when occupancy data points goes from "false" to "true" (e.g. rising edge).
With this occupiedTime meta data point, I can now generate bar charts showing the total occupied time by hour and possible manipulating the pointValues to generate a new series in percent. Next I will have to figure out how to do histogram (binning) the different occupied time.
BR,
Ricardo -
Ok, I can help expand, however, is this data inserted at set intervals or only when there is a change in state?
Fox
-
Hi Matt,
The occupancy data point's logging type is set to "When point value changes".
BR,
Ricardo -
Roger, Ill have something for you to look at later tonight. Thank you for making an effort.
Generally, if you log at as the data comes in, its easier to filter with a window filter for ensuring you do not have false positives. But if you are happy with the quality of the data, I shall work with that.Fox
-
Here is something I quickly threw together to illustrate my point. When doing the pie chart, just get the length of the pointValues array for each datapoint in your timeframe,
Each of the variables are context points in a virtual datasource.var prevState = state.lastValue(1);print(prevState) if(state.value && !prevState.value) { timeTracker.set(0); LOG.info("timestracker set") } else if(prevState.value && !state.value) { var prevTimestamp = timeTracker.time; var newTimestamp = state.time; var timespent = (newTimestamp - prevTimestamp)/60000.0; //In minutes timeTracker.set(timespent,newTimestamp); LOG.info("time spent") LOG.info(timespent) if(timespent<1) { //LOG.info("less than one") lessThanOne.set(timespent); } else if(timespent>=1 && timespent<10) { //LOG.info("less than ten") lessThanTen.set(timespent,newTimestamp); } else if(timespent>=10) { //LOG.info("more than ten") moreThanTen.set(timespent,newTimestamp); } }
-
Hi Matt,
Do you think we can do this dynamically with AngularJS rather than with data points? One advantage doing it dynamically is we can change the bin group dynamically. What do you think?
BR,
Ricardo -
Of course, one of my suggestions was doing the whole thing as a reusable directive. If you can think of it, the only limitations are hardware and imagination
Fox