Skip to content

Commit

Permalink
Add python script and dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
seblucas committed Jan 3, 2018
1 parent 31c6cb3 commit 50987aa
Show file tree
Hide file tree
Showing 4 changed files with 351 additions and 0 deletions.
48 changes: 48 additions & 0 deletions bh1750.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/python
import smbus
import time

# Define some constants from the datasheet

DEVICE = 0x23 # Default device I2C address

POWER_DOWN = 0x00 # No active state
POWER_ON = 0x01 # Power on
RESET = 0x07 # Reset data register value

# Start measurement at 4lx resolution. Time typically 16ms.
CONTINUOUS_LOW_RES_MODE = 0x13
# Start measurement at 1lx resolution. Time typically 120ms
CONTINUOUS_HIGH_RES_MODE_1 = 0x10
# Start measurement at 0.5lx resolution. Time typically 120ms
CONTINUOUS_HIGH_RES_MODE_2 = 0x11
# Start measurement at 1lx resolution. Time typically 120ms
# Device is automatically set to Power Down after measurement.
ONE_TIME_HIGH_RES_MODE_1 = 0x20
# Start measurement at 0.5lx resolution. Time typically 120ms
# Device is automatically set to Power Down after measurement.
ONE_TIME_HIGH_RES_MODE_2 = 0x21
# Start measurement at 1lx resolution. Time typically 120ms
# Device is automatically set to Power Down after measurement.
ONE_TIME_LOW_RES_MODE = 0x23

#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def convertToNumber(data):
# Simple function to convert 2 bytes of data
# into a decimal number
return ((data[1] + (256 * data[0])) / 1.2)

def readLight(addr=DEVICE):
data = bus.read_i2c_block_data(addr,ONE_TIME_HIGH_RES_MODE_1)
return convertToNumber(data)

def main():

while True:
print ("Light Level : " + str(readLight()) + " lx")
time.sleep(0.5)

if __name__=="__main__":
main()
171 changes: 171 additions & 0 deletions bme280.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/usr/bin/python
#--------------------------------------
# ___ ___ _ ____
# / _ \/ _ \(_) __/__ __ __
# / , _/ ___/ /\ \/ _ \/ // /
# /_/|_/_/ /_/___/ .__/\_, /
# /_/ /___/
#
# bme280.py
# Read data from a digital pressure sensor.
#
# Official datasheet available from :
# https://www.bosch-sensortec.com/bst/products/all_products/bme280
#
# Author : Matt Hawkins
# Date : 25/07/2016
#
# http://www.raspberrypi-spy.co.uk/
#
#--------------------------------------
import smbus
import time
from ctypes import c_short
from ctypes import c_byte
from ctypes import c_ubyte

DEVICE = 0x76 # Default device I2C address


bus = smbus.SMBus(1) # Rev 2 Pi, Pi 2 & Pi 3 uses bus 1
# Rev 1 Pi uses bus 0

def getShort(data, index):
# return two bytes from data as a signed 16-bit value
return c_short((data[index+1] << 8) + data[index]).value

def getUShort(data, index):
# return two bytes from data as an unsigned 16-bit value
return (data[index+1] << 8) + data[index]

def getChar(data,index):
# return one byte from data as a signed char
result = data[index]
if result > 127:
result -= 256
return result

def getUChar(data,index):
# return one byte from data as an unsigned char
result = data[index] & 0xFF
return result

def readBME280ID(addr=DEVICE):
# Chip ID Register Address
REG_ID = 0xD0
(chip_id, chip_version) = bus.read_i2c_block_data(addr, REG_ID, 2)
return (chip_id, chip_version)

def readBME280All(addr=DEVICE):
# Register Addresses
REG_DATA = 0xF7
REG_CONTROL = 0xF4
REG_CONFIG = 0xF5

REG_CONTROL_HUM = 0xF2
REG_HUM_MSB = 0xFD
REG_HUM_LSB = 0xFE

# Oversample setting - page 27
OVERSAMPLE_TEMP = 2
OVERSAMPLE_PRES = 2
MODE = 1

# Oversample setting for humidity register - page 26
OVERSAMPLE_HUM = 2
bus.write_byte_data(addr, REG_CONTROL_HUM, OVERSAMPLE_HUM)

control = OVERSAMPLE_TEMP<<5 | OVERSAMPLE_PRES<<2 | MODE
bus.write_byte_data(addr, REG_CONTROL, control)

# Read blocks of calibration data from EEPROM
# See Page 22 data sheet
cal1 = bus.read_i2c_block_data(addr, 0x88, 24)
cal2 = bus.read_i2c_block_data(addr, 0xA1, 1)
cal3 = bus.read_i2c_block_data(addr, 0xE1, 7)

# Convert byte data to word values
dig_T1 = getUShort(cal1, 0)
dig_T2 = getShort(cal1, 2)
dig_T3 = getShort(cal1, 4)

dig_P1 = getUShort(cal1, 6)
dig_P2 = getShort(cal1, 8)
dig_P3 = getShort(cal1, 10)
dig_P4 = getShort(cal1, 12)
dig_P5 = getShort(cal1, 14)
dig_P6 = getShort(cal1, 16)
dig_P7 = getShort(cal1, 18)
dig_P8 = getShort(cal1, 20)
dig_P9 = getShort(cal1, 22)

dig_H1 = getUChar(cal2, 0)
dig_H2 = getShort(cal3, 0)
dig_H3 = getUChar(cal3, 2)

dig_H4 = getChar(cal3, 3)
dig_H4 = (dig_H4 << 24) >> 20
dig_H4 = dig_H4 | (getChar(cal3, 4) & 0x0F)

dig_H5 = getChar(cal3, 5)
dig_H5 = (dig_H5 << 24) >> 20
dig_H5 = dig_H5 | (getUChar(cal3, 4) >> 4 & 0x0F)

dig_H6 = getChar(cal3, 6)

# Wait in ms (Datasheet Appendix B: Measurement time and current calculation)
wait_time = 1.25 + (2.3 * OVERSAMPLE_TEMP) + ((2.3 * OVERSAMPLE_PRES) + 0.575) + ((2.3 * OVERSAMPLE_HUM)+0.575)
time.sleep(wait_time/1000) # Wait the required time

# Read temperature/pressure/humidity
data = bus.read_i2c_block_data(addr, REG_DATA, 8)
pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
hum_raw = (data[6] << 8) | data[7]

#Refine temperature
var1 = ((((temp_raw>>3)-(dig_T1<<1)))*(dig_T2)) >> 11 var2 = (((((temp_raw>>4) - (dig_T1)) * ((temp_raw>>4) - (dig_T1))) >> 12) * (dig_T3)) >> 14
t_fine = var1+var2
temperature = float(((t_fine * 5) + 128) >> 8);

# Refine pressure and adjust for temperature
var1 = t_fine / 2.0 - 64000.0
var2 = var1 * var1 * dig_P6 / 32768.0
var2 = var2 + var1 * dig_P5 * 2.0
var2 = var2 / 4.0 + dig_P4 * 65536.0
var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
var1 = (1.0 + var1 / 32768.0) * dig_P1
if var1 == 0:
pressure=0
else:
pressure = 1048576.0 - pres_raw
pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1
var1 = dig_P9 * pressure * pressure / 2147483648.0
var2 = pressure * dig_P8 / 32768.0
pressure = pressure + (var1 + var2 + dig_P7) / 16.0

# Refine humidity
humidity = t_fine - 76800.0
humidity = (hum_raw - (dig_H4 * 64.0 + dig_H5 / 16384.0 * humidity)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * humidity * (1.0 + dig_H3 / 67108864.0 * humidity)))
humidity = humidity * (1.0 - dig_H1 * humidity / 524288.0)
if humidity > 100:
humidity = 100
elif humidity < 0:
humidity = 0

return temperature/100.0,pressure/100.0,humidity

def main():

(chip_id, chip_version) = readBME280ID()
print ("Chip ID :", chip_id)
print ("Version :", chip_version)

temperature,pressure,humidity = readBME280All()

print ("Temperature : ", temperature, "C")
print ("Pressure : ", pressure, "hPa")
print ("Humidity : ", humidity, "%")

if __name__=="__main__":
main()
Expand Down
97 changes: 97 additions & 0 deletions i2c2mqtt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: latin-1 -*-
#
# i2c2mqtt.py
#
# Copyright 2016 Sébastien Lucas <[email protected]>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
#

import bh1750
import bme280
import si7201
import time, json, argparse
import paho.mqtt.publish as publish # pip install paho-mqtt

verbose = False

def debug(msg):
if verbose:
print (msg + "\n")

def getI2cSensors(devices):
tstamp = int(time.time())

newObject = {"time": tstamp}

if not isinstance(devices, list):
newObject['message'] = 'No devices specified.'
return (False, newObject)

if 'bh750' in devices:
###### Get luminosity ##
lux = bh1750.readLight()
# Drop the first (usually bad)
lux = bh1750.readLight()
newObject['lum'] = int (lux)
debug ("Light Level : " + str(newObject['lum']) + " lx")

if 'si7201' in devices:
###### Get temperature & humidity from si7201 ##
T = si7201.readTemperature()
newObject['temp'] = round (T, 1)
RH = si7201.readHumidity()
newObject['hum'] = int (RH)
debug ("Temperature : " + str(newObject['temp']) + " °C")
debug ("Humidity : " + str(newObject['hum']) + " %")

if 'bme280' in devices:
###### Get temperature, pressure & humidity from bme280 ##
T, P, RH = bme280.readBME280All()
newObject['temp'] = round (T, 1)
newObject['hum'] = int (RH)
newObject['pres'] = int(P)
debug ("Temperature : " + str(newObject['temp']) + " °C")
debug ("Humidity : " + str(newObject['hum']) + " %")
debug ("Pressure : " + str(newObject['pres']) + " hPa")

return (True, newObject)

parser = argparse.ArgumentParser(description='Read current temperature,illuminance and humidity from i2c sensors and send them to a MQTT broker.')
parser.add_argument('-d', '--device', dest='devices', action="append",
help='Specify the devices to probe in the I2C bus. Can be called many times.')
parser.add_argument('-m', '--mqtt-host', dest='host', action="store", default="127.0.0.1",
help='Specify the MQTT host to connect to.')
parser.add_argument('-n', '--dry-run', dest='dryRun', action="store_true", default=False,
help='No data will be sent to the MQTT broker.')
parser.add_argument('-t', '--topic', dest='topic', action="store", default="sensor/i2c",
help='The MQTT topic on which to publish the message (if it was a success).')
parser.add_argument('-T', '--topic-error', dest='topicError', action="store", default="error/sensor/i2c", metavar="TOPIC",
help='The MQTT topic on which to publish the message (if it wasn\'t a success).')
parser.add_argument('-v', '--verbose', dest='verbose', action="store_true", default=False,
help='Enable debug messages.')

args = parser.parse_args()
verbose = args.verbose;

status, data = getI2cSensors(args.devices)
jsonString = json.dumps(data)
if status:
debug("Success with message (for current readings) <{0}>".format(jsonString))
if not args.dryRun:
publish.single(args.topic, jsonString, hostname=args.host)
else:
debug("Failure with message <{0}>".format(jsonString))
if not args.dryRun:
publish.single(args.topicError, jsonString, hostname=args.host)
35 changes: 35 additions & 0 deletions si7201.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/python
# -*- coding: latin-1 -*-

import smbus
bus = smbus.SMBus(1)
address = 0x40

def crc(data):
rem = 0
for b in data:
rem ^= b
for bit in range(8):
if rem & 128:
rem = (rem << 1) ^ 0x31
else:
rem = (rem << 1)
return rem & 0xFF

def readTemperature():
r = bus.read_i2c_block_data(address,0xE3)
t_val = (r[0]<<8) + r[1]
return ((175.72 * t_val)/65536.0) - 46.85

def readHumidity():
r = bus.read_i2c_block_data(address,0xE5)
rh_val = (r[0]<<8) + r[1]
return ((125.0 * rh_val)/65536.0) - 6.0

def main():
print ("Temperature : " + str(readTemperature()) + " °C")
print ("Humidity : " + str(readHumidity()) + " %")

if __name__=="__main__":
main()

0 comments on commit 50987aa

Please sign in to comment.