TinkerForge WeatherStation

Building your own Weather-Station is fun and it is even more fun if you can use all kind of electronics but with a focus on programming. Start with a simple in house sensor station which can extended in almost anyway you can imagine. For me TinkerForge is a perfect start to get into The Internet of Things. It a bit like using Arduino boards, but you do not need soldering or a breadboard to attach sensors, LED’s, displays and other components.

All the information from the Weather-station I store in a InfluxDB time series database and Grafana-server is used to present the data.

In this Blog I will explain how to prepare a basic TinkerForge setup, connected over WiFi, running a simple Java program to communicate with your TinkerForge setup, which stores the data in a simple .txt file. You need some basic Java skills, a PC/laptop with a Java development environment prepared, you know how the compile and run a Java program from the command line. In a future Blog I will explain how to use node-red to do some interesting things with the data in the .txt files.

Basic setup tinkerforge

Before we go have a look how to run the Weather Station, first a few basics about the TinkerForge components. You can find much information on the TinkerForge website.

  • Bricks: Stackable microcontroller modules which can be controlled of USB.
  • Bricklets: Non-stackable sensor/actuator modules that add features to a Brick.
  • Master Extensions: Modules that provide WiFi, Ethernet or RS485 connectivity.
  • Power Supplies: Modules to power a stack of Brick.

Bricks you can stack and the lowermost Brick is always the Master Brick, this Brick is responsible for the communication between all the boards in the stack and the controlling device. From your controlling device you can access the Brick stack via micro-USB, you will need to install the Brick Daemon (brickd) and the Brick Viewer (brickv) as described on the TinkerForge website.

To get started you only need 1 masterbrick and 1 bricklet, but as this post is about my own WeatherStation it has a bit more components. If have added a WiFi Extension to the WeatherStation which enables me to setup the Station without the need for PC or Raspberry PI next to it. I also added a temperature and a humidity Bricklet and mounted it on mounting plate during testing / development, connected it to my PC USB-port.

Start the Brick Viewer application, make sure “localhost” and port “4223” are selected and hit the connect button and your Brick details should be visible.

If needed you can update or flash components, but that’s out of scope for this blog. Configuring the WiFi configuration can be done via the “Master Brick 2.1” tab.

For testing, update the “Client Mode” part as needed for your home-network and click “Reset”. After a few seconds the Brick Viewer will re-connect, check the Status by selecting “Show Status” at the bottom of the “Master Brick” tab.

Disconnect the USB-cable and connect your Tinkerforge setup to a USB-power supply. Lets check all is working fine over WiFi. Go to your Brick Viewer and change the Host from “localhost” to the IP-address you configured and click connect. If all went well you are now connected to your TinkerForge setup over WiFi. Now we are ready to prepare a simple Java program to get data from the Sensor Bricklets.

A simple JAVA program to fetch data

TinkerForge offers options for a long list of supported programming languages. I will use Java for this example. I am not trying to prepare the most efficient setup, but my focus is to use as many different tools and options as possible. For example it would be more efficient to write the sensor data in a Database direct from the Java program. But if I did that, I would not be able to work with node-red, MQTT and all those other things I want to learn. I am not a developer so I have no intention to show off my minor dev-skills, I started with the example programs from TinkerForge and added the option to store the sensor-data in text-files. The code can be found at the bottom of this Blog. On the TinkerForge there is a detailed description of the Java code, the TinkerForge API, and how everything works together. But the TinkerForge code does not store the sensor data, my updated code does store the data.

The code is for the WeatherStation components, so you need a MasterBrick, WiFi extension (or Ethernet Extension) and four Bricklets; LCD 20×4, AmbientLight, Humidity and Barometer. If you only bought the WeatherStation without the Wifi or Ethernet Extension, you can still run the code. Just make sure you change the HOST variable (line 220) in the code to “localhost” and attach the WeatherStation to your PC/Laptop or a Rapsberry PI running your Java program.

I run an Intel NUC as my central Home Automation / IoT server and have setup the required folder structure to run the java program. I start the application with nohup &, so if I disconnected from the terminal session the program will keep running.

Starting the WeatherStation Java application

2 Things will now happen, first you should see your Weatherstation LCD screen to show sensor information and in the data sub-directory you should see 4 files showing up which are regular updated with new sensor information.

The next steps

With the Weatherstation up and running and data coming in, we can start to think about extending the TinkerForge setup and work on better ways to present the data. Like we did for our Public Observatory in Hellendoorn. Which includes a number of internal sensors, an outdoor weather station, barometer and an UV-sensor.

THe WEATHERSTATION code

import com.tinkerforge.IPConnection;
import com.tinkerforge.NetworkException;
import com.tinkerforge.BrickletLCD20x4;
import com.tinkerforge.BrickletAmbientLight;
import com.tinkerforge.BrickletAmbientLightV2;
import com.tinkerforge.BrickletHumidity;
import com.tinkerforge.BrickletBarometer;

import static java.nio.file.StandardOpenOption.*;
import java.nio.file.*;
import java.text.SimpleDateFormat;
import java.io.*;
import java.util.*;

class WeatherListener implements IPConnection.EnumerateListener,
                                 IPConnection.ConnectedListener,
                                 BrickletAmbientLight.IlluminanceListener,
                                 BrickletAmbientLightV2.IlluminanceListener,
                                 BrickletHumidity.HumidityListener,
                                 BrickletBarometer.AirPressureListener {
	private IPConnection ipcon = null;
	private BrickletLCD20x4 brickletLCD = null;
	private BrickletAmbientLight brickletAmbientLight = null;
	private BrickletAmbientLightV2 brickletAmbientLightV2 = null;
	private BrickletHumidity brickletHumidity = null;
	private BrickletBarometer brickletBarometer = null;

	public WeatherListener(IPConnection ipcon) {
		this.ipcon = ipcon;
	}

	
	public void illuminance(int illuminance) {
			// Write to file & LCD 
			double illuminanceValue = illuminance/10.0;
			String illumination = Double.toString(illuminanceValue);
			writetoFile("Illumination" , illumination);
			
			String lcd_text = String.format("Illuminanc %6.2f 1x", illuminance/10.0);
			try {
				brickletLCD.writeLine((short)0, (short)0, lcd_text );
				} catch(com.tinkerforge.TinkerforgeException e) {
			}
    }

	
	public void illuminance(long illuminance) {
			// Write to file & LCD
			double illuminanceValue = illuminance/10.0;
			String illumination = Double.toString(illuminanceValue);
			writetoFile("illumintion" , illumination);

			String lcd_text = String.format("Illuminanc %6.2f 1x", illuminance/10.0);
			try {
				brickletLCD.writeLine((short)0, (short)0, lcd_text );
				} catch(com.tinkerforge.TinkerforgeException e) {
			}
    }

	
	public void humidity(int humidity) {
			// Write to file & LCD
			double humidityValue = humidity/10.0;
			String humi = Double.toString(humidityValue);
			writetoFile("humidity" , humi);	
			
		    String text = String.format("Humidity   %6.2f %%", humidity/10.0);
		    try {
		    		brickletLCD.writeLine((short)1, (short)0, text);
		    		} catch(com.tinkerforge.TinkerforgeException e) {
		    }
    }

	
	public void airPressure(int airPressure) {
			// Write to file & LCD
			double airPressureValue = airPressure/1000.0;
			String Pressure = Double.toString(airPressureValue);
			writetoFile("mbar" , Pressure);
			
		    String text = String.format("Air Press %7.2f mb", airPressure/1000.0);
		    try {
		    		brickletLCD.writeLine((short)2, (short)0, text);
		    		} catch(com.tinkerforge.TinkerforgeException e) {
		    }
		    
		    
			// Temperature handling on barometer bricklet	
			if(brickletBarometer != null) {
				int temperature;
				try {
					temperature = brickletBarometer.getChipTemperature();
				} catch(com.tinkerforge.TinkerforgeException e) {
					System.out.println("Could not get temperature: " + e);
					return;
				}
				// Write to file
				double temp = temperature/100.0;
				String airTemperatureValue = Double.toString(temp);
				writetoFile("celcius" , airTemperatureValue);	
				
			    text = String.format("Temperature %5.2f %cC", temperature/100.0, 0xDF);
			    try {
			    		brickletLCD.writeLine((short)3, (short)0, text);
			    		} catch(com.tinkerforge.TinkerforgeException e) {
			    	}
			}
	}

	
	public void enumerate(String uid, String connectedUid, char position,
	                      short[] hardwareVersion, short[] firmwareVersion,
	                      int deviceIdentifier, short enumerationType) {
		if(enumerationType == IPConnection.ENUMERATION_TYPE_CONNECTED ||
		   enumerationType == IPConnection.ENUMERATION_TYPE_AVAILABLE) {
            if(deviceIdentifier == BrickletLCD20x4.DEVICE_IDENTIFIER) {
                try {
                    brickletLCD = new BrickletLCD20x4(uid, ipcon);
                    brickletLCD.clearDisplay();
                    brickletLCD.backlightOn();
                    System.out.println("LCD 20x4 initialized");
                } catch(com.tinkerforge.TinkerforgeException e) {
                    brickletLCD = null;
                    System.out.println("LCD 20x4 init failed: " + e);
                }
            }   else if(deviceIdentifier == BrickletAmbientLight.DEVICE_IDENTIFIER) {
				try {
					brickletAmbientLight = new BrickletAmbientLight(uid, ipcon);
					brickletAmbientLight.setIlluminanceCallbackPeriod(30000);
					brickletAmbientLight.addIlluminanceListener(this);
					System.out.println("Ambient Light initialized");
				} catch(com.tinkerforge.TinkerforgeException e) {
					brickletAmbientLight = null;
					System.out.println("Ambient Light init failed: " + e);
				}
			} else if(deviceIdentifier == BrickletAmbientLightV2.DEVICE_IDENTIFIER) {
				try {
					brickletAmbientLightV2 = new BrickletAmbientLightV2(uid, ipcon);
					brickletAmbientLightV2.setConfiguration(BrickletAmbientLightV2.ILLUMINANCE_RANGE_64000LUX,
					                                        BrickletAmbientLightV2.INTEGRATION_TIME_200MS);
					brickletAmbientLightV2.setIlluminanceCallbackPeriod(30000);
					brickletAmbientLightV2.addIlluminanceListener(this);
					System.out.println("Ambient Light 2.0 initialized");
				} catch(com.tinkerforge.TinkerforgeException e) {
					brickletAmbientLightV2 = null;
					System.out.println("Ambient Light 2.0 init failed: " + e);
				}
			} else if(deviceIdentifier == BrickletHumidity.DEVICE_IDENTIFIER) {
				try {
					brickletHumidity = new BrickletHumidity(uid, ipcon);
					brickletHumidity.setHumidityCallbackPeriod(30000);
					brickletHumidity.addHumidityListener(this);
					System.out.println("Humidity initialized");
				} catch(com.tinkerforge.TinkerforgeException e) {
					brickletHumidity = null;
					System.out.println("Humidity Inside init failed: " + e);
				}
			} else if(deviceIdentifier == BrickletBarometer.DEVICE_IDENTIFIER) {
				try {
					brickletBarometer = new BrickletBarometer(uid, ipcon);
					brickletBarometer.setAirPressureCallbackPeriod(30000);
					brickletBarometer.addAirPressureListener(this);
					System.out.println("Barometer initialized");
				} catch(com.tinkerforge.TinkerforgeException e) {
					brickletBarometer = null;
					System.out.println("Barometer Inside init failed: " + e);
				}
			}
		}
	}

	
	public void connected(short connectedReason) {
		if(connectedReason == IPConnection.CONNECT_REASON_AUTO_RECONNECT) {
			System.out.println("Auto Reconnect");

			while(true) {
				try {
					ipcon.enumerate();
					break;
				} catch(com.tinkerforge.NotConnectedException e) {
				}

				try {
					Thread.sleep(10000);
				} catch(InterruptedException ei) {
				}
			}
		}
	}
	
	
	public void writetoFile( String property, String value ) {
		
		//Prepare log-line
		//String text = property + "," + value;
		String log_text = value + "\n";
				
		//Convert string to byte array
		byte data[] = log_text.getBytes();
		
		//Set log-file name
		String logfileName = property + ".txt";
		
		//Set log-dir name
		String logfileDir = "./data/";
		
		Path p = Paths.get(logfileDir+logfileName);
		try (OutputStream out = new BufferedOutputStream(
				Files.newOutputStream(p, CREATE, APPEND))) {
				out.write(data, 0, data.length);
		} catch (IOException x) {
			System.err.println(x);
		}
	}
}


public class WeatherStation {
	private static final String HOST = "192.168.2.180";
	private static final int PORT = 4223;
	private static IPConnection ipcon = null;
	private static WeatherListener weatherListener = null;
	

	public static void main(String args[]) throws java.net.UnknownHostException, java.io.IOException {
		ipcon = new IPConnection();
		

		while(true) {
			try {
				ipcon.connect(HOST, PORT);
				break;
			} catch(com.tinkerforge.AlreadyConnectedException e) {
			} catch (NetworkException e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
			}

			try {
				Thread.sleep(10000);
			} catch(InterruptedException e) {
			}
		}

		weatherListener = new WeatherListener(ipcon);
		ipcon.addEnumerateListener(weatherListener);
		ipcon.addConnectedListener(weatherListener);

		while(true) {
			try {
				ipcon.enumerate();
				break;
			} catch(com.tinkerforge.NotConnectedException e) {
			}

			try {
				Thread.sleep(10000);
			} catch(InterruptedException ei) {
			}
		}

		try {
			while (true){
				Thread.sleep(10000);
			}
		} catch(InterruptedException e) {
		}
 
		try {
			ipcon.disconnect();
		} catch(com.tinkerforge.NotConnectedException e) {
		}
	}
}

One thought on “TinkerForge WeatherStation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s