fix this thing
- add PM10 + PM2.5 sensors - rebrand / translate texts to german - make it work with current API TODO: - proper translation service? - load sensors from API instead of hardcode - make box an URL param - make it work with current node - sync scroll between charts
This commit is contained in:
parent
fcbe8f53f8
commit
c4aec1ce04
12 changed files with 99 additions and 39 deletions
|
@ -1 +0,0 @@
|
||||||
sense.devseed.com
|
|
|
@ -31,14 +31,20 @@ export function fetchSensorData (sensor, toDate) {
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
|
.then(json => {
|
||||||
|
return json.sort((a, b) => {
|
||||||
|
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
||||||
|
});
|
||||||
|
})
|
||||||
.then(json => {
|
.then(json => {
|
||||||
dispatch(receiveSensorData(sensor, json));
|
dispatch(receiveSensorData(sensor, json));
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
// dispatch(receiveSensorData(sensor, json));
|
// dispatch(receiveSensorData(sensor, json));
|
||||||
// }, Math.ceil(Math.random() * 5000));
|
// }, Math.ceil(Math.random() * 2000));
|
||||||
}, e => {
|
})
|
||||||
|
.catch(e => {
|
||||||
console.log('e', e);
|
console.log('e', e);
|
||||||
return dispatch(receiveSensorData(null, null, 'Data not available'));
|
return dispatch(receiveSensorData(sensor, null, 'Data not available'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,3 +13,9 @@ export const RECEIVE_SENSOR_DATA_UV = 'RECEIVE_SENSOR_DATA_UV';
|
||||||
|
|
||||||
export const REQUEST_SENSOR_DATA_HUMIDITY = 'REQUEST_SENSOR_DATA_HUMIDITY';
|
export const REQUEST_SENSOR_DATA_HUMIDITY = 'REQUEST_SENSOR_DATA_HUMIDITY';
|
||||||
export const RECEIVE_SENSOR_DATA_HUMIDITY = 'RECEIVE_SENSOR_DATA_HUMIDITY';
|
export const RECEIVE_SENSOR_DATA_HUMIDITY = 'RECEIVE_SENSOR_DATA_HUMIDITY';
|
||||||
|
|
||||||
|
export const REQUEST_SENSOR_DATA_PM10 = 'REQUEST_SENSOR_DATA_PM10';
|
||||||
|
export const RECEIVE_SENSOR_DATA_PM10 = 'RECEIVE_SENSOR_DATA_PM10';
|
||||||
|
|
||||||
|
export const REQUEST_SENSOR_DATA_PM25 = 'REQUEST_SENSOR_DATA_PM25';
|
||||||
|
export const RECEIVE_SENSOR_DATA_PM25 = 'RECEIVE_SENSOR_DATA_PM25';
|
||||||
|
|
|
@ -23,7 +23,6 @@ var LineChart = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
// console.log('LineChart componentDidMount');
|
|
||||||
// Debounce event.
|
// Debounce event.
|
||||||
this.onWindowResize = _.debounce(this.onWindowResize, 200);
|
this.onWindowResize = _.debounce(this.onWindowResize, 200);
|
||||||
|
|
||||||
|
@ -38,13 +37,11 @@ var LineChart = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function () {
|
componentWillUnmount: function () {
|
||||||
// console.log('LineChart componentWillUnmount');
|
|
||||||
window.removeEventListener('resize', this.onWindowResize);
|
window.removeEventListener('resize', this.onWindowResize);
|
||||||
this.chart.destroy();
|
this.chart.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate: function (prevProps/* prevState */) {
|
componentDidUpdate: function (prevProps) {
|
||||||
console.log('LineChart componentDidUpdate');
|
|
||||||
this.chart.pauseUpdate();
|
this.chart.pauseUpdate();
|
||||||
if (prevProps.data !== this.props.data) {
|
if (prevProps.data !== this.props.data) {
|
||||||
this.chart.data(this.props.data);
|
this.chart.data(this.props.data);
|
||||||
|
|
|
@ -60,12 +60,14 @@ var SensorWidget = React.createClass({
|
||||||
data={plotData} />
|
data={plotData} />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{!plotData.length && fetching ? <p className='card__loading'>Loading Data...</p> : null}
|
{!plotData.length ? <p className='card__loading'>
|
||||||
|
{fetching ? 'Lade Daten...' : 'Keine Daten verfügbar'}
|
||||||
|
</p> : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='metrics'>
|
<div className='metrics'>
|
||||||
<ul className='metrics__list'>
|
<ul className='metrics__list'>
|
||||||
<li><strong>{avgs !== null ? numDisplay(avgs.today, 1, unit) : '--'}</strong> avg today</li>
|
<li><strong>{avgs !== null ? numDisplay(avgs.today, 1, unit) : '--'}</strong> ∅ heute</li>
|
||||||
<li><strong>{avgs !== null ? numDisplay(avgs.yesterday, 1, unit) : '--'}</strong> avg yesterday</li>
|
<li><strong>{avgs !== null ? numDisplay(avgs.yesterday, 1, unit) : '--'}</strong> ∅ gestern</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,14 +4,17 @@
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
environment: 'production',
|
environment: 'production',
|
||||||
api: 'http://opensensemap.org:8000',
|
api: 'https://api.opensensemap.org',
|
||||||
|
title: 'Begga Weer',
|
||||||
senseBox: {
|
senseBox: {
|
||||||
id: '570629b945fd40c8197462fb',
|
id: '5b26181b1fef04001b69093c',
|
||||||
'sensorId--uv': '570629b945fd40c8197462fd',
|
'sensorId--pm25': '5b26181b1fef04001b69093d',
|
||||||
'sensorId--luminosity': '570629b945fd40c8197462fe',
|
'sensorId--pm10': '5b26181b1fef04001b69093e',
|
||||||
'sensorId--pressure': '570629b945fd40c8197462ff',
|
'sensorId--uv': '5b26181b1fef04001b69093f',
|
||||||
'sensorId--humidity': '570629b945fd40c819746300',
|
'sensorId--luminosity': '5b26181b1fef04001b690940',
|
||||||
'sensorId--temperature': '570629b945fd40c819746301'
|
'sensorId--pressure': '5b26181b1fef04001b690941',
|
||||||
|
'sensorId--humidity': '5b26181b1fef04001b690942',
|
||||||
|
'sensorId--temperature': '5b26181b1fef04001b690943'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ const sensorLuminosity = sensorReducerFactory('luminosity');
|
||||||
const sensorPressure = sensorReducerFactory('pressure');
|
const sensorPressure = sensorReducerFactory('pressure');
|
||||||
const sensorHumidity = sensorReducerFactory('humidity');
|
const sensorHumidity = sensorReducerFactory('humidity');
|
||||||
const sensorTemperature = sensorReducerFactory('temperature');
|
const sensorTemperature = sensorReducerFactory('temperature');
|
||||||
|
const sensorPm10 = sensorReducerFactory('pm10');
|
||||||
|
const sensorPm25 = sensorReducerFactory('pm25');
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
routing: routeReducer,
|
routing: routeReducer,
|
||||||
|
@ -36,5 +38,7 @@ export default combineReducers({
|
||||||
sensorLuminosity,
|
sensorLuminosity,
|
||||||
sensorPressure,
|
sensorPressure,
|
||||||
sensorHumidity,
|
sensorHumidity,
|
||||||
sensorTemperature
|
sensorTemperature,
|
||||||
|
sensorPm10,
|
||||||
|
sensorPm25,
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ module.exports.numDisplay = function (n, dec = 2, suffix = '', nan = '--') {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.formatDate = function (date) {
|
module.exports.formatDate = function (date) {
|
||||||
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
|
||||||
let hour = date.getHours();
|
let hour = date.getHours();
|
||||||
hour = hour < 10 ? `0${hour}` : hour;
|
hour = hour < 10 ? `0${hour}` : hour;
|
||||||
let minute = date.getMinutes();
|
let minute = date.getMinutes();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
var App = React.createClass({
|
var App = React.createClass({
|
||||||
displayName: 'App',
|
displayName: 'App',
|
||||||
|
@ -15,8 +16,8 @@ var App = React.createClass({
|
||||||
<header className='site-header' role='banner'>
|
<header className='site-header' role='banner'>
|
||||||
<div className='inner'>
|
<div className='inner'>
|
||||||
<div className='site-headline'>
|
<div className='site-headline'>
|
||||||
<h1 className='site-title'>Devseed Sense Lisbon
|
<h1 className='site-title'>
|
||||||
{/* <a href='/' title='Visit homepage'>Glacial Inferno</a> */}
|
<a href={'https://opensensemap.org/explore/' + config.senseBox.id}>{config.title}</a>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,7 +27,7 @@ var App = React.createClass({
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</main>
|
</main>
|
||||||
<footer className='site-footer' role='footer'>
|
<footer className='site-footer' role='footer'>
|
||||||
<p>Made with love by <a href='https://developmentseed.org' title='Visit Development Seed website'>Development Seed</a> using <a href='http://opensensemap.org' title='Visit OpenSenseMap website'>OpenSenseMap</a> data</p>
|
<p> Made with love by <a href='https://developmentseed.org' title='Visit Development Seed website' target="_blank">Development Seed</a> using <a href={'https://opensensemap.org/explore/' + config.senseBox.id} title='Visit openSenseMap website' target="_blank">openSenseMap</a> data </p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,7 +26,9 @@ var Home = React.createClass({
|
||||||
sensorLuminosity: sensorProps,
|
sensorLuminosity: sensorProps,
|
||||||
sensorPressure: sensorProps,
|
sensorPressure: sensorProps,
|
||||||
sensorHumidity: sensorProps,
|
sensorHumidity: sensorProps,
|
||||||
sensorTemperature: sensorProps
|
sensorTemperature: sensorProps,
|
||||||
|
sensorPm10: sensorProps,
|
||||||
|
sensorPm25: sensorProps,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Having measurements every minute is too much. Group them.
|
// Having measurements every minute is too much. Group them.
|
||||||
|
@ -42,7 +44,7 @@ var Home = React.createClass({
|
||||||
prepareData: function (rawData) {
|
prepareData: function (rawData) {
|
||||||
var data = null;
|
var data = null;
|
||||||
|
|
||||||
if (rawData) {
|
if (rawData && rawData.length) {
|
||||||
data = [];
|
data = [];
|
||||||
rawData[0].value = +rawData[0].value;
|
rawData[0].value = +rawData[0].value;
|
||||||
let bucket = [rawData[0]];
|
let bucket = [rawData[0]];
|
||||||
|
@ -127,6 +129,8 @@ var Home = React.createClass({
|
||||||
this.props._requestSensorData('uv', daysAgo3);
|
this.props._requestSensorData('uv', daysAgo3);
|
||||||
this.props._requestSensorData('luminosity', daysAgo3);
|
this.props._requestSensorData('luminosity', daysAgo3);
|
||||||
this.props._requestSensorData('pressure', daysAgo3);
|
this.props._requestSensorData('pressure', daysAgo3);
|
||||||
|
this.props._requestSensorData('pm10', daysAgo3);
|
||||||
|
this.props._requestSensorData('pm25', daysAgo3);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
|
@ -148,6 +152,8 @@ var Home = React.createClass({
|
||||||
let sensorUvData = this.prepareData(this.props.sensorUv.data);
|
let sensorUvData = this.prepareData(this.props.sensorUv.data);
|
||||||
let sensorLuminosityData = this.prepareData(this.props.sensorLuminosity.data);
|
let sensorLuminosityData = this.prepareData(this.props.sensorLuminosity.data);
|
||||||
let sensorPressureData = this.prepareData(this.props.sensorPressure.data);
|
let sensorPressureData = this.prepareData(this.props.sensorPressure.data);
|
||||||
|
let sensorPm10Data = this.prepareData(this.props.sensorPm10.data);
|
||||||
|
let sensorPm25Data = this.prepareData(this.props.sensorPm25.data);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className='page'>
|
<section className='page'>
|
||||||
|
@ -167,7 +173,7 @@ var Home = React.createClass({
|
||||||
className='card--temp'
|
className='card--temp'
|
||||||
fetching={this.props.sensorTemperature.fetching}
|
fetching={this.props.sensorTemperature.fetching}
|
||||||
fetched={this.props.sensorTemperature.fetched}
|
fetched={this.props.sensorTemperature.fetched}
|
||||||
title='Temperature'
|
title='Temperatur'
|
||||||
lastReading={sensorTemperatureData.last}
|
lastReading={sensorTemperatureData.last}
|
||||||
avgs={sensorTemperatureData.avgs}
|
avgs={sensorTemperatureData.avgs}
|
||||||
plotData={sensorTemperatureData.data}
|
plotData={sensorTemperatureData.data}
|
||||||
|
@ -181,7 +187,7 @@ var Home = React.createClass({
|
||||||
className='card--hum'
|
className='card--hum'
|
||||||
fetching={this.props.sensorHumidity.fetching}
|
fetching={this.props.sensorHumidity.fetching}
|
||||||
fetched={this.props.sensorHumidity.fetched}
|
fetched={this.props.sensorHumidity.fetched}
|
||||||
title='Humidity'
|
title='rel. Luftfeuchte'
|
||||||
lastReading={sensorHumidityData.last}
|
lastReading={sensorHumidityData.last}
|
||||||
avgs={sensorHumidityData.avgs}
|
avgs={sensorHumidityData.avgs}
|
||||||
plotData={sensorHumidityData.data}
|
plotData={sensorHumidityData.data}
|
||||||
|
@ -195,7 +201,7 @@ var Home = React.createClass({
|
||||||
className='card--uv'
|
className='card--uv'
|
||||||
fetching={this.props.sensorUv.fetching}
|
fetching={this.props.sensorUv.fetching}
|
||||||
fetched={this.props.sensorUv.fetched}
|
fetched={this.props.sensorUv.fetched}
|
||||||
title='Uv light'
|
title='Uv Licht'
|
||||||
lastReading={sensorUvData.last}
|
lastReading={sensorUvData.last}
|
||||||
avgs={sensorUvData.avgs}
|
avgs={sensorUvData.avgs}
|
||||||
plotData={sensorUvData.data}
|
plotData={sensorUvData.data}
|
||||||
|
@ -209,7 +215,7 @@ var Home = React.createClass({
|
||||||
className='card--lux'
|
className='card--lux'
|
||||||
fetching={this.props.sensorLuminosity.fetching}
|
fetching={this.props.sensorLuminosity.fetching}
|
||||||
fetched={this.props.sensorLuminosity.fetched}
|
fetched={this.props.sensorLuminosity.fetched}
|
||||||
title='Luminosity'
|
title='Helligkeit'
|
||||||
lastReading={sensorLuminosityData.last}
|
lastReading={sensorLuminosityData.last}
|
||||||
avgs={sensorLuminosityData.avgs}
|
avgs={sensorLuminosityData.avgs}
|
||||||
plotData={sensorLuminosityData.data}
|
plotData={sensorLuminosityData.data}
|
||||||
|
@ -223,7 +229,7 @@ var Home = React.createClass({
|
||||||
className='card--press'
|
className='card--press'
|
||||||
fetching={this.props.sensorPressure.fetching}
|
fetching={this.props.sensorPressure.fetching}
|
||||||
fetched={this.props.sensorPressure.fetched}
|
fetched={this.props.sensorPressure.fetched}
|
||||||
title='Air Pressure'
|
title='Luftdruck'
|
||||||
lastReading={sensorPressureData.last}
|
lastReading={sensorPressureData.last}
|
||||||
avgs={sensorPressureData.avgs}
|
avgs={sensorPressureData.avgs}
|
||||||
plotData={sensorPressureData.data}
|
plotData={sensorPressureData.data}
|
||||||
|
@ -233,6 +239,34 @@ var Home = React.createClass({
|
||||||
unit=' hPa'
|
unit=' hPa'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SensorWidget
|
||||||
|
className='card--pm'
|
||||||
|
fetching={this.props.sensorPm10.fetching}
|
||||||
|
fetched={this.props.sensorPm10.fetched}
|
||||||
|
title='Feinstaub 10 μm'
|
||||||
|
lastReading={sensorPm10Data.last}
|
||||||
|
avgs={sensorPm10Data.avgs}
|
||||||
|
plotData={sensorPm10Data.data}
|
||||||
|
axisLineMax={30}
|
||||||
|
axisLineVal={10}
|
||||||
|
axisLineMin={0}
|
||||||
|
unit=' μg/m³'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SensorWidget
|
||||||
|
className='card--pm'
|
||||||
|
fetching={this.props.sensorPm25.fetching}
|
||||||
|
fetched={this.props.sensorPm25.fetched}
|
||||||
|
title='Feinstaub 2.5 μm'
|
||||||
|
lastReading={sensorPm25Data.last}
|
||||||
|
avgs={sensorPm25Data.avgs}
|
||||||
|
plotData={sensorPm25Data.data}
|
||||||
|
axisLineMax={30}
|
||||||
|
axisLineVal={10}
|
||||||
|
axisLineMin={0}
|
||||||
|
unit=' μg/m³'
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
@ -250,7 +284,9 @@ function selector (state) {
|
||||||
sensorLuminosity: state.sensorLuminosity,
|
sensorLuminosity: state.sensorLuminosity,
|
||||||
sensorPressure: state.sensorPressure,
|
sensorPressure: state.sensorPressure,
|
||||||
sensorHumidity: state.sensorHumidity,
|
sensorHumidity: state.sensorHumidity,
|
||||||
sensorTemperature: state.sensorTemperature
|
sensorTemperature: state.sensorTemperature,
|
||||||
|
sensorPm10: state.sensorPm10,
|
||||||
|
sensorPm25: state.sensorPm25,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,6 +277,12 @@ a:active {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.card--press {
|
&.card--press {
|
||||||
|
.infographic {
|
||||||
|
background: linear-gradient(#0d60dd, rgb(52, 122, 196));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card--pm {
|
||||||
.infographic {
|
.infographic {
|
||||||
background: linear-gradient(#616161, #607D8B);
|
background: linear-gradient(#616161, #607D8B);
|
||||||
}
|
}
|
||||||
|
@ -298,4 +304,4 @@ a:active {
|
||||||
p {
|
p {
|
||||||
opacity: 0.64;
|
opacity: 0.64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
<meta name="description" content="Devseed sense dashboards" />
|
<meta name="description" content="Devseed sense dashboards" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
|
||||||
<title>Devseed Sense - Lisbon</title>
|
<title>Begga Weer</title>
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta name="twitter:card" content="summary" />
|
<!-- <meta name="twitter:card" content="summary" /> -->
|
||||||
<meta name="twitter:site" content="@developmentseed" />
|
<!-- <meta name="twitter:site" content="@developmentseed" /> -->
|
||||||
<meta name="twitter:title" content="Devseed Sense - Lisbon">
|
<!-- <meta name="twitter:title" content="Devseed Sense - Lisbon"> -->
|
||||||
<meta name="twitter:description" content="Devseed sense dashboards." />
|
<!-- <meta name="twitter:description" content="Devseed sense dashboards." /> -->
|
||||||
<meta name="twitter:image:src" content="assets/graphics/meta/default-meta-image.png" /
|
<!-- <meta name="twitter:image:src" content="assets/graphics/meta/default-meta-image.png" / -->
|
||||||
<!--/ Twitter -->
|
<!--/ Twitter -->
|
||||||
|
|
||||||
<!-- OG -->
|
<!-- OG -->
|
||||||
<meta property="og:site_name" content="Devseed Sense - Lisbon" />
|
<meta property="og:site_name" content="Devseed Sense - Lisbon" />
|
||||||
|
|
Loading…
Add table
Reference in a new issue