OK, take two. It works after some tweaking. This is my first program in
twenty-five years and first in Python ever, so I'm sure it's ugly. But it
works.
This goes into weewx.conf
[BMP280]
col_temp = extraTemp1
col_pres = barometer
pressure_oversampling = 4
temperature_oversampling = 2
filter = 2
sample_delay = 1
i2c_channel = 1
i2c_device = 119
mode = 3
On Friday, April 7, 2017 at 9:56:59 PM UTC-4, Tom Keffer wrote:
>
> That looks right. At least in theory. :-)
>
> One thing I should note, and maybe you have already done this, but the
> main weewx loop will block when it hits read_raw_data(). You need to make
> sure it doesn't delay things too long. A second or two is fine, but you
> don't want to be waiting half a minute for new data. If there's any chance
> of this, you'll need to either figure out how to include a timeout inside
> read_raw_data(), or do the data acquisition in a separate thread.
>
> -tk
>
>
>
> On Fri, Apr 7, 2017 at 6:37 PM, Craig Thom <crai...@gmail.com
> <javascript:>> wrote:
>
>> OK, just so I'm understanding this. This starts at the bottom of the
>> __init__. col_press and col_temp are strings read from my [BMP280] section
>> of weewx.conf that contain where the data should go, like "barometer" and
>> "extraTemp1". And I divide the corrected pressure by 100 because it's in
>> Pascals, which are 100 mbar/hPa.
>>
>> self.bind(weewx.NEW_LOOP_PACKET, self.new_loop_packet)
>>
>>
>> def new_loop_packet(self, event)
>>
>>
>> sensor_init()
>> raw_pres, raw_temp = read_raw_data()
>> pres_Pa, temp_C = calibrate_raw_data(raw_pres, raw_temp)
>>
>> pres_tuple = weewx.units.convertStd((pres_Pa/100, "mbar",
>> "group_pressure"), packet['usUnits'])
>> temp_tuple = weewx.units.convertStd((temp_C, "degree_C",
>> "group_temperature"), packet['usUnits'])
>>
>> event.record[col_pres] = pres_tuple.value
>> event.record[col_temp] = temp_tuple.value
>>
>>
>>
>>
>> On Friday, April 7, 2017 at 9:11:02 AM UTC-4, Tom Keffer wrote:
>>>
>>> I am new to Python and objects, really, since it's been over twenty
>>>> years since I wrote anything. What it looks like to me, for the service,
>>>> is that weewx is going to create an instance of the class I define in the
>>>> service file and call the function that's bound to my chosen event, right?
>>>>
>>>>
>>> That's correct.
>>>
>>>
>>>
>>>> And if I go with NEW_LOOP_PACKET rather than NEW_ARCHIVE_RECORD, do I
>>>> still need to make sure it gets included in the archive record, or will
>>>> that happen automatically? Or do I bind to both?
>>>>
>>>
>>> Just add your new observations to the LOOP packet.
>>>
>>> LOOP packets are compiled by the "accumulators". They keep track of
>>> mins, maxes, sums, and counts. These are then used to turn the stream of
>>> LOOP packets into archive records.
>>>
>>> What actually happens depends on whether the user is using software or
>>> hardware record generation. If software, at the end of an archive interval,
>>> all the observation types are extracted out of the accumulators and turned
>>> into an archive record. If hardware, the actual archive record comes from
>>> the console, however, starting with v3.7.0, this record gets augmented by
>>> any additional types that can be extracted out of the accumulators. So,
>>> your new types will get included that way.
>>>
>>> Either way, if it's in the LOOP packet, you're good.
>>>
>>> -tk
>>>
>>>
>
import time
import smbus
import syslog
import weewx
from weewx.engine import StdService
# Inherit from the base class StdService:
class bmp(StdService):
def __init__(self, engine, config_dict):
# Pass the initialization information on to my superclass:
super(bmp, self).__init__(engine, config_dict)
self.col_temp = config_dict['BMP280']['col_temp']
self.col_pres = config_dict['BMP280']['col_pres']
self.osrs_p = int(config_dict['BMP280']['pressure_oversampling'])
self.osrs_t = int(config_dict['BMP280']['temperature_oversampling'])
self.filter = int(config_dict['BMP280']['filter'])
self.t_sb = int(config_dict['BMP280']['sample_delay'])
self.i2c_channel = int(config_dict['BMP280']['i2c_channel'])
self.i2c_device = int(config_dict['BMP280']['i2c_device'])
self.mode = int(config_dict['BMP280']['mode'])
self.reg_calib = 0x88
self.reg_ID = 0xD0
self.reg_reset = 0xE0
self.reg_status = 0xF3
self.reg_ctrl_meas = 0xF4
self.reg_config = 0xF5
self.reg_data = 0xF7
self.bus = smbus.SMBus(self.i2c_channel)
self.bind(weewx.NEW_LOOP_PACKET, self.new_loop_packet)
def new_loop_packet(self, event):
self.sensor_init()
raw_pres, raw_temp = self.read_raw_data()
pres_Pa, temp_C = self.calibrate_raw_data(raw_pres, raw_temp)
pres_tuple = weewx.units.convertStd((pres_Pa/100, "mbar", "group_pressure"),event.packet['usUnits'])
temp_tuple = weewx.units.convertStd((temp_C, "degree_C", "group_temperature"), event.packet['usUnits'])
event.packet[self.col_pres] = pres_tuple[0]
event.packet[self.col_temp] = temp_tuple[0]
def sensor_init(self):
config_new = (self.t_sb >> 5) + (self.filter << 2)
ctrl_meas_new = (self.osrs_t <<5) + (self.osrs_p <<2) + self.mode
self.bus.write_byte(self.i2c_device, self.reg_config | 0x80)
config = self.bus.read_byte(self.i2c_device)
# Neither know nor care what bit 1 is
config = config & 0xFD
if (config != config_new):
self.bus.write_byte_data(self.i2c_device,self.reg_config,config_new)
#don't know if it needs the pause, but it only happens once
time.sleep(0.2)
self.bus.write_byte(self.i2c_device, self.reg_ctrl_meas | 0x80)
ctrl_meas = self.bus.read_byte(self.i2c_device)
if (ctrl_meas != ctrl_meas_new):
self.bus.write_byte_data(self.i2c_device,self.reg_ctrl_meas,ctrl_meas_new)
# If in forced mode this will happen every time.
# One reading is taken after it is set.
time.sleep(0.2)
def read_raw_data(self):
"""
The data sheet said to do this as a block read because you want
to read all the data before it changes, but I couldn't figure out
how to do that. Instead I do six straight reads (the chip increments
the register number) instead of a while loop with the write each time.
"""
self.bus.write_byte(self.i2c_device, self.reg_data | 0x80)
p1 = self.bus.read_byte(self.i2c_device)
p2 = self.bus.read_byte(self.i2c_device)
p3 = self.bus.read_byte(self.i2c_device)
t1 = self.bus.read_byte(self.i2c_device)
t2 = self.bus.read_byte(self.i2c_device)
t3 = self.bus.read_byte(self.i2c_device)
raw_p = (p1 << 12) + (p2 << 4) + (p3 >>4)
raw_t = (t1 << 12) + (t2 << 4) + (t3 >>4)
return raw_p, raw_t
def to_signed (self,x):
if x > 32767 :
x = x - 65536
return x
def calibrate_raw_data (self,raw_pr,raw_tm):
raw_pressure = float(raw_pr)
raw_temperature = float(raw_tm)
calibration_data = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
"""
I'm doing the while loop hear because these are fixed values and aren't
going to change. This is the calibration data determined at the
factory after the chip's manufacture.
"""
counter = 0
while counter < 24:
self.bus.write_byte(self.i2c_device, (self.reg_calib | 0x80) + counter)
calibration_data[counter] = self.bus.read_byte(self.i2c_device)
counter = counter + 1
dig_T1 = calibration_data[0] + (calibration_data[1] << 8)
dig_T2 = self.to_signed(calibration_data[2] + (calibration_data[3] << 8))
dig_T3 = self.to_signed(calibration_data[4] + (calibration_data[5] << 8))
dig_P1 = calibration_data[6] + (calibration_data[7] << 8)
dig_P2 = self.to_signed(calibration_data[8] + (calibration_data[9] << 8))
dig_P3 = self.to_signed(calibration_data[10] + (calibration_data[11] << 8))
dig_P4 = self.to_signed(calibration_data[12] + (calibration_data[13] << 8))
dig_P5 = self.to_signed(calibration_data[14] + (calibration_data[15] << 8))
dig_P6 = self.to_signed(calibration_data[16] + (calibration_data[17] << 8))
dig_P7 = self.to_signed(calibration_data[18] + (calibration_data[19] << 8))
dig_P8 = self.to_signed(calibration_data[20] + (calibration_data[21] << 8))
dig_P9 = self.to_signed(calibration_data[22] + (calibration_data[23] << 8))
# calibration formulae from data sheet
var1 = (raw_temperature/16384.0 - dig_T1/1024.0) * dig_T2
var2 = ((raw_temperature/131072.0 - dig_T1/8192.0) *
(raw_temperature/131072.0 - dig_T1/8192.0)) * dig_T3
t_fine = var1 + var2
T = (var1 + var2)/5120.0
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
p = 1048576.0 - raw_pressure
p = (p - (var2/4096.0)) * 6250.0 / var1
var1 = dig_P9 * p * p / 2147483648.0
var2 = p * dig_P8 / 32768.0
p = p + (var1 + var2 + dig_P7) /16.0
return p, T