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
 
    

Reply via email to