How about build a weather station with Beaglebone Black and Node.JS?

I’m able to get some sensor data with Beaglebone Black by the help of Adafruit-Raspberry-Pi-Python-Code on my HMC6352 and HTU21D driver, but what’s next?

Sep 2014: Merging the application with the new OpenPythonSensor driver library, and deploy all the software (MongoDB, Sensor data gather and save with Python, Backend/Frontend application with Node.JS) on a single Beaglebone Black board.


By pushing the sensor data (Temperature, Humidity, Pressure, UVIndex) into a database, an internet front-end application is able to pull and display the data to the users.

Screenshot with plot


Embedded solution: A Beaglebone Black (Ubuntu) with HTU21D (Temperature / Humidity), BMP180(Temperature / Pressure) and SI1145 (Proximity/UV/Ambient Light) sensor. A Python script driven software measures the environment data and push data set to database (MongoDB).

Internet based front-end / back-end solution: Node.JS with Express and Mongoose. Back-end Node.JS code to query the database and send to front-end Angular JS function by AJAX. Supported by jQuery, Bootstrap and Chart.JS.

Screenshot with data


Demo is available at here. Code is shared under MIT License and can be accessed here on Github.

Beaglebone Black with Sensors

Python Library for HTU21D Humidity Sensor on Beaglebone Black and Raspberry Pi with Adafruit_I2C

Here is a python library for the HTU21D Humidity Sensor Module with data output of temperature and relative humidity. Code works well with Beaglebone Black and should also works with Raspberry Pi.

Looks like there is some I2C address issue with this driver on the Pi. Please use with caution. I only did some test for this code on a Beaglebone Black with a Sparkfun HTU21D sensor module.

The HTU21D has an I2C address of 0x40, but it won’t respond to the i2cdetect command on Beaglebone Black stock image.

Also note this module will not accept any unexpected i2c data write/read.

Library and example code can be checked out at Github.

import time
from Adafruit_I2C import Adafruit_I2C
# ===========================================================================
# HTU21D Class
# ===========================================================================
class HTU21D:
	i2c = None
	# HTU21D Address
	address = 0x40
	# Commands
	# Constructor
	def __init__(self):
		self.i2c = Adafruit_I2C(self.address)
	def readUserRegister(self):
		# Read a byte
		value = self.i2c.readU8(self.READ_USER_REG)
		return value
	def readTemperatureData(self):
		# value[0], value[1]: Raw temperature data
		# value[2]: CRC
		value = self.i2c.readList(self.TRIGGER_TEMP_MEASURE_HOLD, 3)
		if not self.crc8check(value):
			return -255
		rawTempData = ( value[0] << 8 ) + value[1]
		# Zero out the status bits but keep them in place
		rawTempData = rawTempData & 0xFFFC;
		# Calculate the actual temperature
		actualTemp = -46.85 + (175.72 * rawTempData / 65536)
		return actualTemp
	def readHumidityData(self):
		# value[0], value[1]: Raw relative humidity data
		# value[2]: CRC
		value = self.i2c.readList(self.TRIGGER_HUMD_MEASURE_HOLD, 3)
		if not self.crc8check(value):
			return -255
		rawRHData = ( value[0] << 8 ) + value[1]
		# Zero out the status bits but keep them in place
		rawRHData = rawRHData & 0xFFFC;
		# Calculate the actual RH
		actualRH = -6 + (125.0 * rawRHData / 65536)
		return actualRH
	def crc8check(self, value):
		remainder = ( ( value[0] << 8 ) + value[1] ) << 8
		remainder |= value[2]
		# POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1
		# divsor = 0x988000 is the 0x0131 polynomial shifted to farthest left of three bytes
		divsor = 0x988000
		for i in range(0, 16):
			if( remainder & 1 << (23 - i) ): 				remainder ^= divsor 			divsor = divsor >> 1
		if remainder == 0:
			return True
			return False

Change i2c bus frequency on Beaglebone Black

Normally one can inspect the i2c bus frequency by

dmesg |grep i2c

According and thanks to the discussion at here

The i2c bus frequency can be changed by edit the Linux device tree dtb file:

1. backup the original .dtb

cp /boot/am335x-boneblack.dtb /boot/am335x-boneblack.dtb.orig

2. generate the dts from the dtb

dtc -I dtb -O dts -o am335x-boneblack.dts /boot/am335x-boneblack.dtb

3. modify the dts with a text editor

i2c@4819c000 {
compatible = "ti,omap4-i2c";
#address-cells = <0x1>;
#size-cells = <0x0>;
ti,hwmods = "i2c3";
reg = <0x4819c000 0x1000>;
interrupts = <0x1e>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x7>;
clock-frequency = <0x186a0>;
linux,phandle = <0x27>;
phandle = <0x27>;

4. generate the dtb from the modified dts

dtc -I dts -O dtb -o am335x-boneblack.dtb am335x-boneblack.dts

Where the i2c@4819c000 is the i2c address:

  • i2c0: 0x44E0B000 (Not available on header)
  • i2c1: 0x4802A000 (Not enabled by default)
  • i2c2: 0x4819C000 (The actual one for configured i2c-1 in Linux, although the register name/expansion port is i2c2)

And the clock-frequency = <0x186a0> is the frequency, 0x186a0 = 100000 = 100KHz here is the default i2c-1 (Expansion port i2c2) frequency for stock beaglebone black image.

5. and finally copy the dtb back to /boot/

cp am335x-boneblack.dtb /boot/am335x-boneblack.dtb


2013 Dec, Keywest, Everglades, Atlanta


Read heading output from compass IC HMC6352 on Beaglebone Black / Raspberry Pi with Adafruit_I2C

Note: Although the datasheet has an I2C address 0x42 on file, the recognized address for this HMC6352 is actually 0x42>>1 which is 0x21.

Also looks like this IC doesn’t care about the register address at all, so put 0x0 in the register address field would be fine.

Code/Driver tested with Beaglebone Black and Sparkfun HMC6352 Module.

The HMC6352 library can be checked out at Github.

import time
from Adafruit_I2C import Adafruit_I2C
# ===========================================================================
# HMC6352 Class
# ===========================================================================
class HMC6352 :
	i2c = None
	# HMC6352 Address
	address = 0x42 >> 1
	# Commands
	# Constructor
	def __init__(self):
		self.i2c = Adafruit_I2C(self.address)
	def userCalibration(self):
		"Write 0x45 for calibration and write 0x4C for leave after 20s"
		self.i2c.write8(0x0, self.CMD_ENTER_USER_CALIBRATION)
		self.i2c.write8(0x0, self.CMD_EXIT_USER_CALIBRATION)
	def readData(self):
		"Read the heading data by write a 0x41 first"
		self.i2c.write8(0x0, self.CMD_READ_DATA)
		# Wait 6 ms
		# Read 2 bytes
		value = self.i2c.readU16(0x0)
		# Reverse the data byte order
		value = self.i2c.reverseByteOrder(value)
		# Convert to 360.0 range from the raw integer value
		value = float('%0.1f'%value)/10
		return value