pimoroni / enviro

MIT License
101 stars 79 forks source link

BME280 configure #123

Closed ChaiFox closed 1 year ago

ChaiFox commented 1 year ago

Whenever I add the configure method from breakout_bme280 to my enviro weather but when ever I include it it fails to actually read anything and no longer responds to pokes. On reboot it will show the white flag as normal then no response from it at all and nothing gets written to mqtt as its set up to do. Unfortunately when it reboots thonny has to be reconnected so if its throwing an error I can't actually see it.

helgibbons commented 1 year ago

Moved this to the Enviro repo for you! Please can you post your code, what version of the firmware you're running and the contents of your log.txt after the crash happens?

ChaiFox commented 1 year ago

Thanks for moving this to the right place. Other than the changes to convert to Imperial in OrderedDict and the few lines in Startup for the bme configure its the stock weather.py. Version is enviro-1.19.7 v0.0.7. As far as the log.txt is concerned its only two lines neither of which is an error so I don't think its crashing per se but rather failing to start correctly with no other info being given.

import time, math
from breakout_bme280 import BreakoutBME280
from breakout_ltr559 import BreakoutLTR559
from machine import Pin, PWM
from pimoroni import Analog
from enviro import i2c, hold_vsys_en_pin 
import enviro.helpers as helpers
from phew import logging

RAIN_MM_PER_TICK = 0.2794

bme280 = BreakoutBME280(i2c, 0x77)
ltr559 = BreakoutLTR559(i2c)

wind_direction_pin = Analog(26)
wind_speed_pin = Pin(9, Pin.IN, Pin.PULL_UP)

def startup():
  import wakeup  

  #adjust sensor values to match oem recommended for weather stations and hopefully help with heating
  #https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf
  # defaults here 
  #https://github.com/pimoroni/pimoroni-pico/tree/main/micropython/modules/breakout_bme280
  bme280.configure(FILTER_COEFF_OFF, STANDBY_TIME_0_5_MS, OVERSAMPLING_1X, OVERSAMPLING_1X, OVERSAMPLING_1X, FORCED_MODE)
  #bme280.configure(FILTER_COEFF_2, STANDBY_TIME_0_5_MS, OVERSAMPLING_16X, OVERSAMPLING_2X, OVERSAMPLING_1X)

  # check if rain sensor triggered wake
  rain_sensor_trigger = wakeup.get_gpio_state() & (1 << 10)

  if rain_sensor_trigger:
    # read the current rain entries
    rain_entries = []
    if helpers.file_exists("rain.txt"):
      with open("rain.txt", "r") as rainfile:
        rain_entries = rainfile.read().split("\n")

    # add new entry
    logging.info("> add new rain trigger at {helpers.datetime_string()}")
    rain_entries.append(helpers.datetime_string())

    # limit number of entries to 190 - each entry is 21 bytes including
    # newline so this keeps the total rain.txt filesize just under one 
    # filesystem block (4096 bytes)
    rain_entries = rain_entries[-190:]

    # write out adjusted rain log
    with open("rain.txt", "w") as rainfile:
      rainfile.write("\n".join(rain_entries))

    # go immediately back to sleep, we'll wake up at next scheduled reading
    hold_vsys_en_pin.init(Pin.IN)

def wind_speed(sample_time_ms=1000):  
  # get initial sensor state
  state = wind_speed_pin.value()

  # create an array for each sensor to log the times when the sensor state changed
  # then we can use those values to calculate an average tick time for each sensor
  ticks = []

  start = time.ticks_ms()
  while time.ticks_ms() - start <= sample_time_ms:
    now = wind_speed_pin.value()
    if now != state: # sensor output changed
      # record the time of the change and update the state
      ticks.append(time.ticks_ms())
      state = now

  # if no sensor connected then we have no readings, skip
  if len(ticks) < 2:
    return 0

  # calculate the average tick between transitions in ms
  average_tick_ms = (ticks[-1] - ticks[0]) / (len(ticks) - 1)

  # work out rotation speed in hz (two ticks per rotation)
  rotation_hz = (1000 / average_tick_ms) / 2

  # calculate the wind speed in metres per second
  radius = 7.0
  circumference = radius * 2.0 * math.pi
  factor = 0.0218  # scaling factor for wind speed in m/s
  wind_m_s = rotation_hz * circumference * factor

  return wind_m_s

def wind_direction():
  # adc reading voltage to cardinal direction taken from our python
  # library - each array index represents a 45 degree step around
  # the compass (index 0 == 0, 1 == 45, 2 == 90, etc.)
  # we find the closest matching value in the array and use the index
  # to determine the heading
  ADC_TO_DEGREES = (0.9, 2.0, 3.0, 2.8, 2.5, 1.5, 0.3, 0.6)

  closest_index = -1
  last_index = None

  # ensure we have two readings that match in a row as otherwise if
  # you read during transition between two values it can glitch
  # fixes https://github.com/pimoroni/enviro/issues/20
  while True:
    value = wind_direction_pin.read_voltage()

    closest_index = -1
    closest_value = float('inf')

    for i in range(8):
      distance = abs(ADC_TO_DEGREES[i] - value)
      if distance < closest_value:
        closest_value = distance
        closest_index = i

    if last_index == closest_index:
      break

    last_index = closest_index

  return closest_index * 45

def timestamp(dt):
  year = int(dt[0:4])
  month = int(dt[5:7])
  day = int(dt[8:10])
  hour = int(dt[11:13])
  minute = int(dt[14:16])
  second = int(dt[17:19])
  return time.mktime((year, month, day, hour, minute, second, 0, 0))

def rainfall():
  if not helpers.file_exists("rain.txt"):
    return 0

  now = timestamp(helpers.datetime_string())
  with open("rain.txt", "r") as rainfile:
    rain_entries = rainfile.read().split("\n")

  # count how many rain ticks in past hour
  amount = 0
  for entry in rain_entries:
    if entry:
      ts = timestamp(entry)
      if now - ts < 60 * 60:
        amount += RAIN_MM_PER_TICK

  return amount

def get_sensor_readings():
  # bme280 returns the register contents immediately and then starts a new reading
  # we want the current reading so do a dummy read to discard register contents first
  bme280.read()
  time.sleep(0.1)
  bme280_data = bme280.read()

  ltr_data = ltr559.get_reading()

  from ucollections import OrderedDict
  return OrderedDict({
    #convert from celcius to fahrenheit
    "temperature": round(((bme280_data[0]*1.8)+32), 2),
    "humidity": round(bme280_data[2], 2),
    "pressure": round(bme280_data[1] / 100.0, 2),
    "light": round(ltr_data[BreakoutLTR559.LUX], 2),
    #convert from m/s to mph
    "wind_speed": round(wind_speed()*2.236936,1),
    "rain": rainfall(),
    "wind_direction": wind_direction()
  })

Log.txt

2022-12-01 15:48:48 [debug    / 115kB] > performing startup
2022-12-01 15:49:40 [debug    / 115kB] > performing startup
ChaiFox commented 1 year ago

I should also mention the same issue happens when using the default args with configure() as well.

helgibbons commented 1 year ago

Recommend updating to the newest firmware, the logging is a lot better!

I'm getting

2022-12-01 16:36:46 [exception / 114kB] ! Traceback (most recent call last):
  File "<stdin>", line 32, in <module>
  File "enviro/__init__.py", line 409, in startup
  File "enviro/boards/weather.py", line 32, in startup
NameError: name 'FILTER_COEFF_OFF' isn't defined

I think you might just need to import all those constants at the beginning of weather.py?

from breakout_bme280 import BreakoutBME280, FILTER_COEFF_OFF, STANDBY_TIME_0_5_MS, OVERSAMPLING_1X, OVERSAMPLING_1X, OVERSAMPLING_1X, FORCED_MODE

ChaiFox commented 1 year ago

Well with updating to the new firmware and adding the imports it still doesn't actually behave correctly. Now the led is just solid and its indicating its getting hung at connecting to wifi which I find doubtful as it connects fine with the line commented out and the device is unresponsive to the poke button.

new log.txt

2022-12-01 18:37:36 [debug    / 115kB] > performing startup
2022-12-01 18:37:36 [info     / 119kB]   - wake reason: usb_powered
2022-12-01 18:37:36 [debug    / 117kB]   - turn on activity led
2022-12-01 18:37:36 [debug    / 115kB] > 104 blocks free out of 212
2022-12-01 18:37:36 [debug    / 113kB] > taking new reading
2022-12-01 18:37:36 [info     / 108kB]   - seconds since last reading: 24
2022-12-01 18:37:38 [debug    /  99kB] > caching reading for upload
2022-12-01 18:37:38 [info     /  95kB] > 1 cache file(s) need uploading
2022-12-01 18:37:38 [info     / 120kB] > connecting to wifi network 'FOO'
helgibbons commented 1 year ago

Ah, sorry that didn't help. Mine seems to be running fine with the addition of your bme.configure line though?

If you run main.py through Thonny does it provide any useful errors?

ChaiFox commented 1 year ago

After checking it today its running just fine so I really have no idea what was going on. Looks like the original problem though was just missing those explicit imports so I'll mark this closed and hope it behaves itself