@ -6,204 +6,106 @@
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "description" content = "IoT around the house" >
< meta name = "description" content = "IoT around the house" >
< title > Life Around< / title >
< title > Life Around< / title >
< link rel = "stylesheet" href = "https://static.10ninox.com/css/bulma.min.css" / >
< link rel = "stylesheet" href = "https://unpkg.com/purecss@1.0.0/build/pure-min.css" integrity = "sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin = "anonymous" >
<!-- [if lte IE 8]>
< link rel = "stylesheet" href = "https://unpkg.com/purecss@1.0.0/build/grids-responsive-old-ie-min.css" >
<![endif]-->
<!-- [if gt IE 8]><! -->
< link rel = "stylesheet" href = "https://unpkg.com/purecss@1.0.0/build/grids-responsive-min.css" >
<!-- <![endif] -->
<!-- [if lte IE 8]>
< link rel = "stylesheet" href = "/combo/1.18.13?/css/layouts/blog-old-ie.css" >
<![endif]-->
<!-- [if gt IE 8]><! -->
< link rel = "stylesheet" href = "http://hq.10ninox.com/styles/blog.css" >
<!-- <![endif] -->
<!-- [if lt IE 9]>
< script src = "http://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7/html5shiv.js" > < / script >
<![endif]-->
< style >
< style >
path {
h1.subtitle>small {
stroke: rgb(237, 40, 1);
font-size: 0.83rem;
stroke-width: 2;
fill: none;
}
.dash {
padding: 1em;
font-size: 16px;
}
.dash-container {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.graph {
position: relative;
width: 250px;
height: 50px;
}
.dash-one {
width: 250px;
text-align: center;
font-size: 1em;
background: #33333322;
padding: 10px 0;
overflow: wrap;
}
.dash-one p {
font-size: 4em;
margin: 0em;
}
.dash-one h2 {
font-size: 1.1em;
margin: 2px 5px;
}
h1 small {
font-size: 0.8rem;
margin: 0 10px;
color: #666;
}
}
< / style >
< / style >
< / head >
< / head >
< body >
< body >
< div id = "layout" class = "pure-g" >
< div class = "container" id = "app" >
<!-- <div class="sidebar pure - u - 1 pure - u - md - 1 - 4">
< div class = "notification" v-if = "message.length > 0" >
< ul class = "device-list" > < / ul >
{{ message }}
< / div > -->
< / div >
< div id = "content" class = "pure-u-1" > < / div >
< div v-for = "group in groups" >
< section class = "hero is-light" >
< div class = "hero-body" >
< div class = "container" >
< h1 class = "title" >
{{ group }}
< / h1 >
< / div >
< / div >
< / section >
< div class = "columns is-multiline" >
< div class = "column is-one-third" v-for = "device in devices[group]" >
< div class = "box has-ribbon" >
< div class = "ribbon is-danger" v-if = "device.needWater" > รดน้ ำด้ วย!< / div >
< h1 class = "title" > {{ device.info.name }}< / h1 >
< h2 class = "subtitle is-6" > {{ device.fromNow }}< / h2 >
< span class = "tag is-light" > {{ device.info.sensor }}< / span >
< span class = "tag is-danger" v-if = "device.needBattery" > เปลี ่ ยน Battery< / span >
< div class = "columns" >
< div class = "column" >
< p > Temperature < small > ºC< / small > < / p >
< h1 class = "subtitle is-1" > {{ device.data.temperature }}< / h1 >
< / div >
< div class = "column" v-if = "device.info.sensor !== 'Xiaomi Mi Flora'" >
< p > ความชื ้ นอากาศ < small > %< / small > < / p >
< h1 class = "subtitle is-1" > {{ device.data.humidity }} < / h1 >
< / div >
< div class = "column" v-if = "device.info.sensor === 'Xiaomi Mi Flora'" >
< p > ความชื ้ นของดิ น < small > %< / small > < / p >
< h1 class = "subtitle is-1" > {{ device.data.moisture }} < / h1 >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< script src = "https://code.jquery.com/jquery-3.1.1.min.js" > < / script >
< script src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js" > < / script >
< script src = "http://code.highcharts.com/highcharts.js" > < / script >
< script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js" > < / script >
< script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js" > < / script >
< script src = "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.14/moment-timezone.min.js" > < / script >
< script src = "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.14/moment-timezone.mi
< script src = "https://d3js.org/d3.v4.js" > < / script >
n.js">< / script >
< script src = "https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js" > < / script >
< script >
< script >
var app = new Vue({
function displayGraph(id, data, width, height, interpolation) {
el: '#app',
//, animate, updateDelay, transitionDelay) {
data: {
var animate = true, updateDelay = 1000, transitionDelay = 1000;
url: { base: 'http://iot.10ninox.com', all: '/all' },
// create an SVG element inside the #graph div that fills 100% of the div
message: '',
var graph = d3.select(id).append("svg:svg");
groups: [],
// X scale will fit values from 0-10 within pixels 0-100
devices: {},
var x = d3.scaleLinear().domain([0, 152]).range([0, width]); // starting point is -5 so the first value doesn't show and slides off the edge as part of the transition
},
// Y scale will fit values from 0-10 within pixels 0-100
created: function() {
var y = d3.scaleLinear().domain([0, 80]).range([0, height]);
this.getDevices()
},
// create a line object that represents the SVN line we're creating
methods: {
var line = d3.line()
getDevices: function() {
// assign the X function to plot our line as we wish
var vm = this
.x(function (d, i) {
axios.get(`${vm.url.base}${vm.url.all}`)
// verbose logging to show what's actually being done
.then(function(resp) {
//console.log('Plotting X value for data point: ' + d + ' using index: ' + i + ' to be at: ' + x(i) + ' using our xScale.');
var data = resp.data
// return the X coordinate where we want to plot this datapoint
vm.groups = Array.from(new Set(resp.data.map((i) => i.group)))
return x(i);
vm.groups.forEach(ele => {
})
vm.devices[ele] = data.filter((i) => {
.y(function (d) {
if (i.group !== ele) return
// verbose logging to show what's actually being done
i.needWater = false
//console.log('Plotting Y value for data point: ' + d + ' to be at: ' + y(d) + " using our yScale.");
i.needBattery = false
// return the Y coordinate where we want to plot this datapoint
var sensor = i.info.sensor.toLowerCase()
return y(d);
if (sensor === 'xiaomi mi flora' || sensor === 'mijia') {
})
i.needBattery = i.data.battery < 10
if (interpolation == "basis") {
line.curve(d3.curveCatmullRom.alpha(0.5))
}
}
if (sensor === 'Xiaomi Mi Flora') {
// display the line by appending an svg:path element with the data line we created above
i.needWater = i.data.moisture < 40 ? true : false
graph.append("svg:path").attr("d", line(data));
// or it can be done like this
//graph.selectAll("path").data([data]).enter().append("svg:path").attr("d", line);
function redrawWithAnimation() {
// update with animation
graph.selectAll("path")
.attr("transform", "translate(" + x(1) + ")") // set the transform to the right by x(1) pixels (6 for the scale we've set) to hide the new value
.data([data]) // set the new data
.attr("d", line) // apply the new data values ... but the new value is hidden at this point off the right of the canvas
.transition() // start a transition to bring the new value into view
.ease(d3.easeLinear)
.duration(transitionDelay * 0.95) // for this demo we want a continual slide so set this to the same as the setInterval amount below
.attr("transform", "translate(" + x(0) + ")"); // animate a slide to the left back to x(0) pixels to reveal the new value
/* thanks to 'barrym' for examples of transform: https://gist.github.com/1137131 */
}
function redrawWithoutAnimation() {
// static update without animation
graph.selectAll("path")
.data([data]) // set the new data
.attr("d", line); // apply the new data values
}
redrawWithoutAnimation();
}
(function () {
var baseUrl = '',
allUrl = baseUrl + '/all',
$sidebar = $('.sidebar'),
$list = $sidebar.find('.device-list'),
$content = $('#content');
var addToList = function(item) {
$list.append(
`< li > < a href = "#${item['device']}" > ` +
`${item["device"]}< / a > < / li > `);
};
var addEleToDashBoard = function(item) {
var data = item['data'];
var xid = item['device'].replace(/:/g, '_')
var tmsp = moment.tz(item['timestamp'], "utc").fromNow()
var str = `< div class = "pure-u-md-1-2 dash" id = "${xid}" > ` +
`< h1 > ${item['info']['name']}< small > ${tmsp}< / small > < / h1 > ` +
`< div class = "dash-container" > ` +
`< div class = "dash-one temperature" > < h2 > Temp< / h2 > < p > ${data['temperature']}< / p > < div class = "graph" id = "${xid}-temperature" > < / div > < / div > ` +
`< div class = "dash-one moisture" > < h2 > Moisture< / h2 > < p > ${data['moisture']}< / p > < div class = "graph" id = "${xid}-moisture" > < / div > < / div > ` +
`< div class = "dash-one humidity" > < h2 > Humidity< / h2 > < p > ${data['humidity']}< / p > < div class = "graph" id = "${xid}-humidity" > < / div > < / div > ` +
`< / div > ` +
`< / div > `;
$content.append(str);
};
var reloadListener = function() {
$('.dash').on('click', function () {
var that = $(this),
id = that.attr('id').replace(/_/g, ':'),
oneUrl = `${baseUrl}/id/${id}?limit=150`;
that.off('click');
$.getJSON(oneUrl, function(data, textStatus, xhr) {
var isFlora = data[0]['info']['sensor'].toLowerCase().indexOf("flora") > -1;
var extra = (isFlora ? 'humidity' : 'moisture');
var ks = ['temperature', extra];
for (var ik in ks) {
var key = ks[ik];
var ll = data.map(function(ele, i) {
return ele['data'][key]
});
var tid = `#${that.attr('id')}-${key}`;
displayGraph(tid, ll, 250, 50, "basic");
}
}
});
i.fromNow = moment.tz(i.timestamp, '').fromNow()
});
return i
}
})
})
$.getJSON(allUrl, function(data, textStatus, xhr) {
})
for (var i=0; i< data.length ; i + + ) {
.catch(function(error){
var x = data[i];
vm.message = 'Error! Could not reach the API. ' + error
addToList(x);
})
addEleToDashBoard(x);
},
var isFlora = x['info']['sensor'].toLowerCase().indexOf("flora") > -1;
var toHide = (isFlora ? 'humidity' : 'moisture');
$('#' + x['device'].replace(/:/g, '_')).find('.'+ toHide).hide();
}
}
reloadListener();
})
});
})(jQuery);
< / script >
< / script >
< / body >
< / body >
< / html >
< / html >