Resetting Notecard I2C communications. Sequence number mismatch

I get the errors below in my console after a sending notes every hour for a few hours. Has anyone seen this before? This may be because I’m checking the signal strength at the same time I’m trying to send (doh!)
cardDetails = card.Transaction({“req”: “card.wireless”})
cardSignal = cardDetails[“net”][“bars”]

Using transaction timeout of 30 seconds.
{“req”:“card.wireless”,“crc”:“000e:3ce09784”}
Resetting Notecard I2C communications.
Sequence number mismatch. Expected 000e, received 000E.
CRC error on response from Notecard.
Sequence number mismatch. Expected 000e, received 000E.
CRC error on response from Notecard.
Sequence number mismatch. Expected 000e, received 000E.
CRC error on response from Notecard.
Sequence number mismatch. Expected 000e, received 000E.
CRC error on response from Notecard.
Sequence number mismatch. Expected 000e, received 000E.
CRC error on response from Notecard.

My notecard settings are

req = {“req”: “hub.set”}
req[“product”] = productUID
req[“mode”] = “periodic”
req[“outbound”] = 1
req[“inbound”] = 12*60
rsp = card.Transaction(req)

Hi bkauf,

Your code’s hitting a bug that we recently fixed in note-python: When checking CRC, treat sequence number and CRC as integers. by haydenroche5 · Pull Request #81 · blues/note-python · GitHub

Prior to this commit, the hex strings for the CRC and sequence number from the Notecard were compared against hex strings computed by the host. If the casing of the hex digits differs between host and Notecard, there can be false CRC errors.

Apologies for the inconvenience. If you pull the latest note-python code from the main branch, the problem should resolve.

We will be releasing a new note-python version with this fix soon.

Thanks!

Hayden
Software Engineer @ Blues

1 Like

Hello,

Thank you for the response, I moved to the new library, I am now seeing errors like the following when sending notes to the hub, I will try to investigate more this week:

Using transaction timeout of 30 seconds. [Errno 5] Input/output error Resetting Notecard I2C communications. Failed to acquire I2C lock

Hi bkauf,

  • Are you able to share the rest of the code, including the part that sets up the I2C port and the OpenI2C object?
  • What platform are you using: Raspberry Pi, MicroPython, something else?

Best,

Hayden

Hi Hayden,

Thank you for the support!

This is a rasberry pi pico connected to a notcard and AHT20 sensor both over i2c using circuit python.

port = busio.I2C(board.GP1, board.GP0) 
card = notecard.OpenI2C(port, 0, 0, debug=True)
#Temp/Humidity Sensor Settings
sensor = adafruit_ahtx0.AHTx0(port)

I have two IF statements in the main while loop, one calling the AHT every few minutes, the other publishing the sensor data every few hours. When the sensor publishes via this code I sometimes get the “Failed to acquire I2C lock” error. Is there an easy way to check if the i2c port is locked before. Do you think this is because I’m checking the hub for new notes right after the send?:

 try:
        req = {"req": "note.add"}
        req["file"] = "data.qo"
        req["sync"] = True
        req["body"] = {json body...}
        rsp = card.Transaction(req)
        
        #Sync with Hub to collect any notes
        req = {"req": "note.get"}
        req["file"] = "my-inbound.qi"
        req["delete"] = True
        rsp = card.Transaction(req)

        if "body" in rsp:
            rspBody = rsp["body"]
             ...
    except Exception as error:
        print('Cannot Connet to HUB', error)
        message = "Cannot Connect to HUB!"

Hi bkauf,

Thank you for the support!

Happy to help. :slight_smile:

Is there an easy way to check if the i2c port is locked before.

I’m not seeing anything in the CircuitPython API docs that’ll give you that information directly. We are using the try_lock method in note-python. We try to acquire the lock 5 times, pausing for 100 ms between tries. If we still can’t get the lock after that, then we raise the exception you’re seeing (“Failed to acquire I2C lock.”).

Do you think this is because I’m checking the hub for new notes right after the send?

That should not matter.

When the sensor publishes via this code I sometimes get the “Failed to acquire I2C lock” error.

Just to confirm, this only happens sometimes? Not always?

I don’t have the exact same hardware as you, but I’ll try to reproduce the problem on my end.

Thanks,

Hayden

Hi bkauf,

I have an Adafruit BME280 module. Its CircuitPython library uses the same underlying Adafruit CircuitPython BusDevice code that your sensor’s library is using. This underlying library is what’s responsible for locking and unlocking the I2C bus.

I’m using the following script to communicate with both the Notecard and the BME280 board over the same I2C bus, and I’m not running into that locking error you’re seeing. I’m also using a Blues Swan as opposed to an RPi Pico.

import notecard
import board
import adafruit_bme280.advanced as adafruit_bme280
import time

port = board.I2C()
card = notecard.OpenI2C(port, 0, 0, debug=True)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(port)

# Change this to match the location's pressure (hPa) at sea level
bme280.sea_level_pressure = 1013.25
bme280.mode = adafruit_bme280.MODE_NORMAL
bme280.standby_period = adafruit_bme280.STANDBY_TC_500
bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16
bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1
bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2
# The sensor will need a moment to gather initial readings
time.sleep(1)

req = {"req": "hub.set"}
req["product"] = "com.blues.hroche:blah"
req["mode"] = "continuous"
card.Transaction(req)

while True:
    print("\nTemperature: %0.1f C" % bme280.temperature)
    print("Humidity: %0.1f %%" % bme280.relative_humidity)
    print("Pressure: %0.1f hPa" % bme280.pressure)
    print("Altitude = %0.2f meters" % bme280.altitude)

    req = {"req": "note.add"}
    req["sync"] = True
    req["file"] = "debug.qo"
    req["body"] = {"temp": bme280.temperature, "humidity": bme280.relative_humidity}
    card.Transaction(req)

    time.sleep(10)

If possible, please share the full source code of your project. That’ll help me spot any differences and possibly reproduce the error on my end.

Thanks!

Hayden

Thank you so much for your help with this Hayden, really appreciate it! My code below for rasberry pi pico. I recently noticed that I can reproduce the issue 100% of the time if I set my report_INTERVAL_SEC variable to 60 minutes which defines when to publish messages to the notehub, if it’s less than that(5 or 10 minutes) everything works fine…very strange! Appreciate any guidance you can provide.


import time
import board
import digitalio
import notecard
import busio
import adafruit_ahtx0
from analogio import AnalogIn
import microcontroller
import watchdog
import time

# Watchdog settings

wdt = microcontroller.watchdog
wdt.timeout= 8 # Set a timeout of the watchdog , max 8 seconds

#Note Card Settings
productUID = "xxxxx"
port = busio.I2C(board.GP1, board.GP0) 
card = notecard.OpenI2C(port, 0, 0, debug=True)

#Temp/Humidity Sensor Settings
sensor = adafruit_ahtx0.AHTx0(port)

#LED Light Settings
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT

# Pin to detect USB Power
powerPin = digitalio.DigitalInOut(board.GP24)

# Starting Variables
# Sync outbound notes to Notehub a max of every 1 minutes if notes are waiting to go out.
outbound_SYNC_MINS = 1
# Sync inbound notes to Notehub a minimum of every 12 hours
inbound_SYNC_MINS = (12*60)
# Read temp sensor every 60 seconds.
sensor_READ_INTERVAL_SEC = (60)
# Publish outbound notes every 1 hour
report_INTERVAL_SEC = (1*60*60)

# Default Temp 
temperature = 20
humidity = 30
power = True
voltage = 0
last_REPORT_SEND_TIME = 0
last_SENSOR_READ_TIME = 0  # use 0 in production 0


# intialize notecard
req = {"req": "hub.set"}
req["product"] = productUID
req["mode"] = "periodic"
req["outbound"] = outbound_SYNC_MINS
req["inbound"] = inbound_SYNC_MINS
rsp = card.Transaction(req)

#Setup pin to read voltage
analog_in = AnalogIn(board.A3)

def get_voltage(pin):
    return (pin.value * 3.3) / 65536

def readSensors():
    wdt.feed()
    global temperature
    global humidity
    global power
    global voltage
    global last_SENSOR_READ_TIME
    global message
   
    last_SENSOR_READ_TIME = time.time()

    try:
        # record last time sensors were read
        print("read started...")
        temperature = sensor.temperature
        humidity = sensor.relative_humidity
        power = powerPin.value
        voltage = get_voltage(analog_in)
    except Exception as error:
        print('Cannot Read read AHT20', error)
        message = "Cannot read AHT20"

# function to send data to the notehub
def publishSystemData(reason, action):

    wdt.feed()
    global message
    global last_REPORT_SEND_TIME  
    
    try:
        print("publish started")
        #add in other data to send
        req = {"req": "note.add"}
        req["file"] = "data.qo"
        req["sync"] = True
        req["body"] = {"temperature": temperature,
                       "humidity": humidity, "power": power, }
        rsp = card.Transaction(req)
        if(rsp):
            last_REPORT_SEND_TIME = time.time() # update last time data sync was done
            getDataFromHub()
    
        message = "GREEN"
    except Exception as error:
        print('Cannot Connect to HUB', error)
        last_REPORT_SEND_TIME = last_REPORT_SEND_TIME+(60*10) # retry  in 10 minutes
        message = "Cannot Connect to HUB!"
         
# function to get data from the notehub
def getDataFromHub():
   
    wdt.feed()

    
    #fetch and new notes on routine sync
    
    try:
        req = {"req": "note.get"}
        req["file"] = "my-inbound.qi"
        req["delete"] = True
        rsp = card.Transaction(req)

        if "body" in rsp:
         .....
        else:
            print("no new notes from hub")
            message = "GREEN"
    except:
        print('Cannot Get Notes from HUB')
        message = "Cannot Get Notes from HUB!"
        

while True:  # main loop
    wdt.mode = watchdog.WatchDogMode.RESET
    wdt.feed()
  

    # read sensors if last sensor read time greater than read interval
    if (time.time()-last_SENSOR_READ_TIME >= sensor_READ_INTERVAL_SEC):
    
        print("reading sensors..."+str(time.time()))
        led.value = True
        time.sleep(0.5)
        led.value = False
        readSensors()  
        time.sleep(4)
        wdt.feed()


    # Send Data to notehub if last report time greater than report interval
    if (time.time()-last_REPORT_SEND_TIME > report_INTERVAL_SEC or last_REPORT_SEND_TIME == 0):
    
        print("publishing data..."+str(time.time()))
        publishSystemData("normal publish, lastsend: "+str(last_REPORT_SEND_TIME), "")
        
   

Hi bkauf,

I’m wondering if this has something to do with the watchdog timer. Looking back to this error message you sent earlier:

Using transaction timeout of 30 seconds. [Errno 5] Input/output error Resetting Notecard I2C communications. Failed to acquire I2C lock

It seems like the watchdog might be expiring in the middle of this transaction. When I’ve seen something like “[Errno 5] Input/output error” in the past, it indicates that the connection to the MCU was lost, which could be indicative of the MCU resetting itself.

Can you try commenting out all the watchdog code and see if the problem goes away? Or setting the watchdog timeout to a larger value, perhaps a minute?

Thanks,

Hayden

Thank you for the help Hayden. The issue seems to go away it I add a few seconds of offset between these two variables.

# Read temp sensor every 60 seconds.
sensor_READ_INTERVAL_SEC = (60)
# Publish outbound notes every 1 hour
report_INTERVAL_SEC = (1*60*60)

It seems the sleep variable does not actually delay the running of the if statements when inside the first if statement so they must have been firing at the exact same times. I’d assume everything fires top down but looks like everything is going at the same time(I think). Anyway working now, thanks again!

Glad you were able to get it working!