This document describes how to build a Java-based weather station using a Raspberry Pi 2 that collects sensor data and sends it to a web client over MQTT and WebSockets. The weather station hardware includes various sensors to measure temperature, humidity, pressure, UV, air quality. A Java program on the Pi reads the sensors and sends the data to a broker over MQTT. A web client subscribes to the MQTT topic over WebSockets and displays charts and readings using JavaScript and HighCharts. The architecture uses MQTT for publish/subscribe between the Pi and client and WebSockets for low-latency updates to the web UI.
2. MARCO PIRRUCCIO
Research and Development Director, Partner @ Kettydo+ srl
E-mail marcopirruccio@gmail.com
LinkedIn www.linkedin.com/in/marcopirruccio
4. HARDWARE SHOPPING LIST
? Raspberry Pi2
? DHT22 (temperature, humidity)
? BMP180 (temperature, pressure, altitude)
? ML8511 (UV intensity)
? TGS2600 (air contaminants)
? MCP3800 (ADC for ML8511 and TGS2600)
? A red and a green LED
? A tactile button switch
5. SOFTWARE INGREDIENTS
On the Raspberry Pi
? Java 8
? Pi4J and WiringPi
? MQTT (Eclipse Paho Java client)
On the web client
? WebSockets (Eclipse Paho JavaScript client)
? JavaScript: jQuery, HighCharts
? HTML, CSS
8. MQTT (MESSAGE QUEUING TELEMETRY TRANSPORT)
? MQTT is a ¡°machine-to-machine¡± (M2M) or ¡°Internet of Things¡± (IoT) connectivity protocol.
? It was designed as an extremely lightweight publish/subscribe messaging transport.
? It was designed for constrained devices and low-bandwidth, high-latency or unreliable networks.
? MQTT was invented by Dr Andy Stanford-Clark of IBM and Arlen Nipper of Arcom (now Eurotech) in 1999.
? It is an application protocol over TCP/IP.
? Quality of service levels:
? 0: at most once delivery
? 1: at least once delivery
? 2: exactly once delivery (there is an increased overhead associated with this quality of service)
9. WEBSOCKETS
? The WebSockets specification was developed as part of the HTML5 initiative.
? The WebSockets standard defines a full-duplex single socket connection over which messages can be
sent between client and server.
? WebSockets provide an enormous reduction in unnecessary network traffic and latency compared to
the unscalable polling and long-polling solutions that were used to simulate a full-duplex connection by
maintaining two connections.
10. JAVA, PI4J, WIRINGPI
? Raspbian includes the official Oracle Java 8 for ARM since the end of 2013. Older versions can install it using apt-get.
? The Pi4J project is intended to provide a friendly object-oriented I/O API and implementation libraries for Java Programmers
to access the full I/O capabilities of the Raspberry Pi platform.
? It abstracts the low-level native integration and interrupt monitoring to enable Java programmers to focus on implementing
their application business logic.
? Main features:
? Control, read and write GPIO pin states
? Listen for GPIO pin state changes (interrupt-based; not polling)
? I2C, SPI, RS232 communication
? WiringPi is a GPIO access library written in C for the BCM2835.
11. WEATHER STATION MAIN CLASS
WeatherStationReader reader = new WeatherStationReader();
WeatherStationWriter writer = WeatherStationWriterFactory.getWriter(Writer.MQTT);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
reader.shutdown();
writer.close();
}
});
while (true) {
WeatherStationData data = reader.read();
writer.write(data);
Thread.sleep(2000);
}
12. WEATHER STATION READER: INITIALIZATION
GpioController controller = GpioFactory.getInstance();
MCP3008 adc = new MCP3008();
ML8511 uv = new ML8511(adc, ML8511_ADC_CHANNEL);
TGS2600 gas = new TGS2600(adc, TGS2600_ADC_CHANNEL);
BMP180 bar = new BMP180();
DHT22 t = new DHT22(DHT22_PIN);
GpioPinDigitalInput button = controller.provisionDigitalInputPin(BUTTON_GPIO, PinPullResistance.PULL_UP);
button.addListener(new GpioPinListenerDigital() {
public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
System.exit(0);
}
});
ActivityNotifier an = new ActivityNotifier(READ_ACTIVITY_NOTIFIER_GPIO, "readerLed");
13. WEATHER STATION READER: READING SENSORS
an.notifyActivity();
WeatherStationData res = new WeatherStationData();
DHT22Response th = t.read();
res.setTemperature((float) th.getTemperature());
res.setHumidity((float) th.getHumidity());
gas.setReferenceHumidity(res.getHumidity()); gas.setReferenceTemperature(res.getTemperature());
TGS2600Response air = gas.read();
res.setAirQuality(air.getResistance()); res.setEthanol((int) air.getC2h5ohPPM()); res.setButane((int) air.getC4h10PPM());
res.setHydrogen((int) air.getH2PPM());
float uvIntensity = uv.read(); res.setUvIntensity(uvIntensity);
final float pressure = bar.readPressure(); res.setPressure(pressure / 100);
14. WEATHER STATION WRITER: INITIALIZATION
String broker = "tcp://iot.eclipse.org:1883";
String clientId = WeatherStation.class.getName();
MemoryPersistence persistence = new MemoryPersistence();
MqttClient client = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
client.connect(connOpts);
ActivityNotifier an = new ActivityNotifier(WRITE_ACTIVITY_NOTIFIER_GPIO, "writerLed");
15. WEATHER STATION WRITER: SENDING DATA
String topic = "/WeatherStation";
int qos = 2;
String json = jsonSerializer.serialize(data);
an.notifyActivity();
MqttMessage message = new MqttMessage(json.getBytes());
message.setQos(qos);
client.publish(topic, message);
16. THE WEB CLIENT: HTML MARKUP
<div id="container-main"></div>
<div>
<div id="container-uv"></div>
<div id="container-aq"></div>
<div id="container-gas">
<table>
<thead>
<tr><td>PPM</td></tr>
</thead>
<tbody>
<tr><td>Ethanol</td><td id="ethanol">0</td></tr>
<tr><td>Butane</td><td id="butane">0</td></tr>
<tr><td>Hydrogen</td><td id="hydrogen">0</td></tr>
</tbody>
</table>
</div>
</div>
17. THE WEB CLIENT: WEBSOCKET
var host = 'ws://iot.eclipse.org/ws';
var topic = '/WeatherStation';
var clientId = "WeatherStationClient";
var client = new Paho.MQTT.Client(host, clientId);
client.onConnectionLost = function(responseObject) { ... };
client.onMessageArrived = function(message) { ... };
client.connect({
onSuccess : function() {
client.subscribe(topic);
}
});
18. THE WEB CLIENT: CHARTS
client.onMessageArrived = function(message) {
var data = JSON.parse(message.payloadString);
var chart = $('#container-main').highcharts();
chart.series[0].addPoint([data.timestamp, data.temperature]);
chart.series[1].addPoint([data.timestamp, data.humidity]);
chart.series[2].addPoint([data.timestamp, data.pressure]);
chart.redraw();
chart = $('#container-uv').highcharts();
var point = chart.series[0].points[0];
point.update(parseFloat(data.uvIntensity.toFixed(2)));
chart = $('#container-aq').highcharts();
point = chart.series[0].points[0];
point.update(parseInt(data.airQuality.toFixed(0)));
$('#ethanol').html(data.ethanol);
$('#butane').html(data.butane);
$('#hydrogen').html(data.hydrogen);
};