Skip to content

Settings are overwritten on startup for OpenFlexure camera #383

Description

@rwb27

Describe the bug
The settings for openflexure_microscope_server.things.camera.picamera.StreamingPiCameraV2 are overwritten with defaults when I run ofm restart or otherwise restart the server

To Reproduce

  • Start up the OpenFlexure Microscope server (I'm using latest v3 branch: !636 6ae8f8d970c7b7e18bc0637d2afd6fc37855be32)
  • Change the camera's exposure time e.g. curl http://localhost:5000/api/v3/camera/exposure_time --request PUT -d 2000
  • Check the change went through e.g. curl http://localhost:5000/api/v3/camera/exposure_time
  • Check the change is reflected in settings/camera/Settings-StreamingPiCameraV2.json
  • Restart the server with ofm restart
  • Observe that the settings file has reverted
  • Observe that the exposure is back to default curl http://localhost:5000/api/v3/camera/exposure_time

It's also possible to observe in the GUI, but this method was easier to use when finding the offending commit.

Expected behaviour
The settings should be remembered across a restart

Additional context
This problem was introduced by #256. The previous merge commit does not exhibit the problem.

This is not simply a blanket failure to remember settings. That would have been caught by unit tests. Other Things on the OpenFlexure server (e.g. the Camera Stage Mapping thing) do correctly remember their settings. The camera hardware is a bit badly-behaved when it comes to settings, so the camera Thing has some complicated logic embedded in various functional settings:

  • When a setting is read, it will attempt to read the value from hardware (if the hardware is running). If the hardware is not running, it will return the cached value (which is initialised to a default.
  • If a setting is read and the cached value does not match the value from the hardware, the cached value and the settings file will be updated.
  • When a setting is written, it will update the cached value and the settings file.
  • When a setting is written, if the camera is running it will also update the hardware.

My guess is that the problem appeared because of some subtle change in how the settings are initialised. This is resulting in the settings file being written during start-up of the Thing, using cached values for (most?) properties.

I think we can probably restructure the settings to get rid of the problem. However, I think it might be preferred to fix it in LabThings if we can. Restructuring the OFM code to be easier to understand would still, I think, be useful - but might be a longer-term change.

A log from before the bug, with a bunch of extra stuff added to the camera class.

Filtered log:

[2026-07-02 10:56:30,303] [INFO] <openflexure_microscope_server.logging> OFM server root logger has been set up at INFO level
[2026-07-02 10:56:30,336] [INFO] <labthings_fastapi.things.camera> Starting picamera __init__
[2026-07-02 10:56:30,341] [INFO] <labthings_fastapi.things.camera> stopping __init__
[2026-07-02 10:56:30,372] [INFO] <labthings_fastapi.things.camera> Setting exposure time to 1984, previous was 500.
[2026-07-02 10:56:30,373] [INFO] <labthings_fastapi.things.camera> Current streaming status: False
[2026-07-02 10:56:31,623] [INFO] <labthings_fastapi.things.camera> starting StreamingPiCamera2.__enter__
[2026-07-02 10:56:31,624] [INFO] <labthings_fastapi.things.camera> starting _initialise_picamera
[2026-07-02 10:56:31,628] [INFO] <openflexure_microscope_server.things.camera.picamera> Creating new Picamera2 object
[2026-07-02 10:56:31,683] [INFO] <labthings_fastapi.things.camera> stopping _initialise_picamera
[2026-07-02 10:56:31,685] [INFO] <labthings_fastapi.things.camera> Getting exposure time. Cached value 1984.
[2026-07-02 10:56:31,685] [INFO] <labthings_fastapi.things.camera> Returning 1984
[2026-07-02 10:56:31,727] [INFO] <openflexure_microscope_server.things.camera.picamera> Starting picamera MJPEG stream...
[2026-07-02 10:56:31,796] [INFO] <labthings_fastapi.things.camera> stopping StreamingPiCamera2.__enter__
Full log ``` [2026-07-02 10:56:30,303] [INFO] OFM server root logger has been set up at INFO level [2026-07-02 10:56:30,336] [INFO] Starting picamera __init__ [2026-07-02 10:56:30,341] [INFO] stopping __init__ [2026-07-02 10:56:30,372] [INFO] Setting exposure time to 1984, previous was 500. [2026-07-02 10:56:30,373] [INFO] Current streaming status: False [2026-07-02 10:56:31,609] [INFO] Started server process [79330] [2026-07-02 10:56:31,610] [INFO] Waiting for application startup. [2026-07-02 10:56:31,623] [INFO] starting StreamingPiCamera2.__enter__ [2026-07-02 10:56:31,624] [INFO] starting _initialise_picamera [2026-07-02 10:56:31,628] [INFO] Creating new Picamera2 object [2026-07-02 10:56:31,680] [INFO] Initialization successful. [2026-07-02 10:56:31,680] [INFO] Camera now open. [2026-07-02 10:56:31,683] [INFO] stopping _initialise_picamera [2026-07-02 10:56:31,685] [INFO] Getting exposure time. Cached value 1984. [2026-07-02 10:56:31,685] [INFO] Returning 1984 [2026-07-02 10:56:31,688] [INFO] Camera configuration has been adjusted! [2026-07-02 10:56:31,690] [INFO] Configuration successful! [2026-07-02 10:56:31,727] [INFO] Starting picamera MJPEG stream... [2026-07-02 10:56:31,761] [INFO] Camera started [2026-07-02 10:56:31,796] [INFO] stopping StreamingPiCamera2.__enter__ [2026-07-02 10:56:31,797] [INFO] Initialising ExtensibleSerialInstrument on port None [2026-07-02 10:56:31,798] [INFO] Updating ESI port settings [2026-07-02 10:56:31,798] [INFO] Opening ESI connection to port None [2026-07-02 10:56:31,806] [INFO] Creating serial.Serial instance... [2026-07-02 10:56:31,808] [INFO] Created Serial(port='/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False) [2026-07-02 10:56:31,808] [INFO] Testing communication to SangaBoard [2026-07-02 10:56:31,808] [INFO] Running firmware checks... [2026-07-02 10:56:31,814] [INFO] Firmware response: Sangaboard Firmware v1.0.4 [2026-07-02 10:56:31,816] [INFO] Success! [2026-07-02 10:56:31,817] [INFO] Creating serial.Serial instance... [2026-07-02 10:56:31,818] [INFO] Created Serial(port='/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False) [2026-07-02 10:56:31,818] [INFO] Testing communication to SangaBoard [2026-07-02 10:56:31,819] [INFO] Running firmware checks... [2026-07-02 10:56:31,824] [INFO] Firmware response: Sangaboard Firmware v1.0.4 [2026-07-02 10:56:31,825] [INFO] Opened ESI connection to port None [2026-07-02 10:56:31,826] [INFO] Checking valid firmware... [2026-07-02 10:56:31,826] [INFO] Running firmware checks... [2026-07-02 10:56:31,831] [INFO] Firmware response: Sangaboard Firmware v1.0.4 [2026-07-02 10:56:31,832] [INFO] Loading modules... [2026-07-02 10:56:31,848] [INFO] Enabling backwards-compatible behaviour on new Sangaboard firmware [2026-07-02 10:56:31,872] [INFO] Application startup complete. [2026-07-02 10:56:31,877] [INFO] Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit) ```
Log showing the problem

Filtered log:

[2026-07-02 11:02:37,670] [INFO] <openflexure_microscope_server.logging> OFM server root logger has been set up at INFO level
[2026-07-02 11:02:37,702] [INFO] <labthings_fastapi.things.camera> Starting picamera __init__
[2026-07-02 11:02:37,713] [INFO] <labthings_fastapi.things.camera> Getting exposure time. Cached value 500.
[2026-07-02 11:02:37,714] [INFO] <labthings_fastapi.things.camera> Returning 500
[2026-07-02 11:02:37,724] [INFO] <labthings_fastapi.things.camera> stopping __init__
[2026-07-02 11:02:37,748] [WARNING] <labthings_fastapi.things.camera> None is not a valid background detector name.
[2026-07-02 11:02:37,749] [INFO] <labthings_fastapi.things.camera> Setting exposure time to 500, previous was 500.
[2026-07-02 11:02:37,749] [INFO] <labthings_fastapi.things.camera> Current streaming status: False
[2026-07-02 11:02:38,873] [INFO] <labthings_fastapi.things.camera> starting StreamingPiCamera2.__enter__
[2026-07-02 11:02:38,874] [INFO] <labthings_fastapi.things.camera> starting _initialise_picamera
[2026-07-02 11:02:38,877] [INFO] <openflexure_microscope_server.things.camera.picamera> Creating new Picamera2 object
[2026-07-02 11:02:38,933] [INFO] <labthings_fastapi.things.camera> stopping _initialise_picamera
[2026-07-02 11:02:38,934] [INFO] <labthings_fastapi.things.camera> Getting exposure time. Cached value 500.
[2026-07-02 11:02:38,935] [INFO] <labthings_fastapi.things.camera> Returning 500
[2026-07-02 11:02:38,975] [INFO] <openflexure_microscope_server.things.camera.picamera> Starting picamera MJPEG stream...
[2026-07-02 11:02:39,032] [INFO] <labthings_fastapi.things.camera> stopping StreamingPiCamera2.__enter__
Full log
[2026-07-02 11:02:37,670] [INFO] <openflexure_microscope_server.logging> OFM server root logger has been set up at INFO level
[2026-07-02 11:02:37,702] [INFO] <labthings_fastapi.things.camera> Starting picamera __init__
[2026-07-02 11:02:37,713] [INFO] <labthings_fastapi.things.camera> Getting exposure time. Cached value 500.
[2026-07-02 11:02:37,714] [INFO] <labthings_fastapi.things.camera> Returning 500
[2026-07-02 11:02:37,724] [INFO] <labthings_fastapi.things.camera> stopping __init__
[2026-07-02 11:02:37,748] [WARNING] <labthings_fastapi.things.camera> None is not a valid background detector name.
[2026-07-02 11:02:37,749] [INFO] <labthings_fastapi.things.camera> Setting exposure time to 500, previous was 500.
[2026-07-02 11:02:37,749] [INFO] <labthings_fastapi.things.camera> Current streaming status: False
[2026-07-02 11:02:38,859] [INFO] <uvicorn> Started server process [80579]
[2026-07-02 11:02:38,860] [INFO] <uvicorn> Waiting for application startup.
[2026-07-02 11:02:38,873] [INFO] <labthings_fastapi.things.camera> starting StreamingPiCamera2.__enter__
[2026-07-02 11:02:38,874] [INFO] <labthings_fastapi.things.camera> starting _initialise_picamera
[2026-07-02 11:02:38,877] [INFO] <openflexure_microscope_server.things.camera.picamera> Creating new Picamera2 object
[2026-07-02 11:02:38,930] [INFO] <picamera2.picamera2> Initialization successful.
[2026-07-02 11:02:38,930] [INFO] <picamera2.picamera2> Camera now open.
[2026-07-02 11:02:38,933] [INFO] <labthings_fastapi.things.camera> stopping _initialise_picamera
[2026-07-02 11:02:38,934] [INFO] <labthings_fastapi.things.camera> Getting exposure time. Cached value 500.
[2026-07-02 11:02:38,935] [INFO] <labthings_fastapi.things.camera> Returning 500
[2026-07-02 11:02:38,938] [INFO] <picamera2.picamera2> Camera configuration has been adjusted!
[2026-07-02 11:02:38,941] [INFO] <picamera2.picamera2> Configuration successful!
[2026-07-02 11:02:38,975] [INFO] <openflexure_microscope_server.things.camera.picamera> Starting picamera MJPEG stream...
[2026-07-02 11:02:39,012] [INFO] <picamera2.picamera2> Camera started
[2026-07-02 11:02:39,032] [INFO] <labthings_fastapi.things.camera> stopping StreamingPiCamera2.__enter__
[2026-07-02 11:02:39,033] [INFO] <sangaboard.sangaboard> Initialising ExtensibleSerialInstrument on port None
[2026-07-02 11:02:39,034] [INFO] <sangaboard.extensible_serial_instrument> Updating ESI port settings
[2026-07-02 11:02:39,035] [INFO] <sangaboard.extensible_serial_instrument> Opening ESI connection to port None
[2026-07-02 11:02:39,042] [INFO] <sangaboard.extensible_serial_instrument> Creating serial.Serial instance...
[2026-07-02 11:02:39,043] [INFO] <sangaboard.extensible_serial_instrument> Created Serial<id=0x7f625491b0, open=True>(port='/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
[2026-07-02 11:02:39,044] [INFO] <sangaboard.sangaboard> Testing communication to SangaBoard
[2026-07-02 11:02:39,044] [INFO] <sangaboard.sangaboard> Running firmware checks...
[2026-07-02 11:02:39,049] [INFO] <sangaboard.sangaboard> Firmware response: Sangaboard Firmware v1.0.4
[2026-07-02 11:02:39,050] [INFO] <sangaboard.extensible_serial_instrument> Success!
[2026-07-02 11:02:39,051] [INFO] <sangaboard.extensible_serial_instrument> Creating serial.Serial instance...
[2026-07-02 11:02:39,052] [INFO] <sangaboard.extensible_serial_instrument> Created Serial<id=0x7f624e0d90, open=True>(port='/dev/ttyAMA0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
[2026-07-02 11:02:39,052] [INFO] <sangaboard.sangaboard> Testing communication to SangaBoard
[2026-07-02 11:02:39,055] [INFO] <sangaboard.sangaboard> Running firmware checks...
[2026-07-02 11:02:39,060] [INFO] <sangaboard.sangaboard> Firmware response: Sangaboard Firmware v1.0.4
[2026-07-02 11:02:39,061] [INFO] <sangaboard.extensible_serial_instrument> Opened ESI connection to port None
[2026-07-02 11:02:39,061] [INFO] <sangaboard.sangaboard> Checking valid firmware...
[2026-07-02 11:02:39,061] [INFO] <sangaboard.sangaboard> Running firmware checks...
[2026-07-02 11:02:39,066] [INFO] <sangaboard.sangaboard> Firmware response: Sangaboard Firmware v1.0.4
[2026-07-02 11:02:39,067] [INFO] <sangaboard.sangaboard> Loading modules...
[2026-07-02 11:02:39,083] [INFO] <sangaboard.sangaboard> Enabling backwards-compatible behaviour on new Sangaboard firmware
[2026-07-02 11:02:39,108] [INFO] <uvicorn> Application startup complete.
[2026-07-02 11:02:39,112] [INFO] <uvicorn> Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions