config.txt reverting after editing on Pi Zero W

I’m trying to use the development image for a serial device. I need to disable Bluetooth and set CPU frequency. I first downloaded the image for the Pi Zero and configured my WiFi credentials using:

sudo balena local configure ~/Downloads/balena-cloud-raspberry-pi-2.54.2+rev1-dev-v11.12.4.img

Then I edited the config.txt in the mounted resin-boot drive to add dtoverlay=pi3-disable-bt.

But after reboot the device reverts the configuration and reboots again. I can see in the journal:

Jun 19 00:06:09 kartlogger 47cf4c543b04[1313]: [event]   Event: Apply boot config in progress {}
Jun 19 00:06:09 kartlogger resin-supervisor[1623]: [event]   Event: Apply boot config in progress {}
Jun 19 00:06:09 kartlogger 47cf4c543b04[1313]: [event]   Event: Apply boot config success {}
Jun 19 00:06:09 kartlogger resin-supervisor[1623]: [event]   Event: Apply boot config success {}
Jun 19 00:06:10 kartlogger 47cf4c543b04[1313]: [event]   Event: Reboot {}
Jun 19 00:06:10 kartlogger resin-supervisor[1623]: [event]   Event: Reboot {}
Jun 19 00:06:10 kartlogger 47cf4c543b04[1313]: [info]    Stopped Supervisor API
Jun 19 00:06:10 kartlogger resin-supervisor[1623]: [info]    Stopped Supervisor API
Jun 19 00:06:12 kartlogger systemd-logind[1251]: System is rebooting.
Connection to kartlogger.local closed by remote host.

Any idea why it is reverting the config.txt file?

Hi

You can modify this locally, or even better from the dashboard - both methods are documented here : Advanced boot settings - Balena Documentation

The article mentions modifying locally before first boot. Is there a way to modify locally after first boot? I am not using the cloud dashboard.

Hi, when you say “I am not using the cloud dashboard”, are you using the images from balenaOS - Run Docker containers on embedded IoT devices? If you download images from the dashboard, you are implicitely using the cloud so the supervisor will sync the local configuration with the cloud.

Correct. I downloaded the Raspberry Pi Zero W development image in from that page.

I have poked around some more and found that the supervisor stores settings in a database file at /resin-data/resin-supervisor/database.sqlite. If I open up the file I can see it has a deviceConfig table with the host config.txt settings. If I update the JSON adding my own config value and reboot, the supervisor will update my config.txt and reboot the device.

Am I missing the more friendly way of editing this deviceConfig table?

Hi @andyshinn, thanks for reporting this

For unmanaged OS images the supervisor should take the provided config.txt values and use those as defaults. Is there any chance you could share the rest of the journal logs (I’m interested in the beginning of the stream).

I will try to replicate this on my side to see if this if this is a bug.

Thanks again!

Sure thing. I attached a journal log with the reboot after I change the config.txt, you can see it boots, applies the supervisor config.txt, then reboots again.

Hi again,

Thanks for sharing the logs. Unfortunately I could not replicate this, these are the steps I followed

In my case the supervisor started normally and the modified configuration remains on /mnt/boot/config.txt.

Are those the right replication steps? Did I miss anything?

I see that a service got killed by the supervisor before rebooting. How did you start that service? Using livepush or did you preload an image?

Did you do anything else after boot?

Thanks again

I am modifying the config.txt after boot. I think maybe that is where the confusion is coming from. Should the values persist with local changes after first boot as well? If not, how can I change the config.txt after first boot on the local dev image?

Hi, thanks for the clarification. I can confirm this is the case, let me explain the behavior you are seeing.

In general the supervisor works by comparing the device ‘current state’ with a ‘target state’, and performs any actions required to get from the first to the second. When connected to the cloud, the target state is given by our API, making the configurations on the cloud the source of truth.

For a device that has not connected yet (or an unmanaged device), there is no target state from the cloud, so the device uses the initial ‘current state’ as the starting target state for the device. This is very useful to have preloaded devices boot without connection to the cloud yet, where the supervisor will use the initial configuration as target until the device can reach to our servers.

In the case of unmanaged, the supervisor will set the initial configuration as target and store that in the database forever, meaning any changes to configurations such as config.txt (the current state) will revert back to the target state once the supervisor is restarted.

I can see this is not entirely ideal in the case of unmanaged devices, but the right solution may require some discussion. I have created an issue in our repo that you can track here Users cannot modify device configurations in unmanaged mode · Issue #1727 · balena-os/balena-supervisor · GitHub

In the meantime, you can set the configuration after boot by using the Local Mode Endpoints which are enabled for unmanaged devices

  • Get the current configuration for the device and store it in a file: curl -X GET http://<your-device-ip>:48484/v2/local/target-state | jq ".state" > state.json
  • Make the changes to the configuration file
  • Update the configuration on the supervisor curl -X POST --header 'Content-type: application/json' -d ./state.json http://<your-device-ip>:48484/v2/local/target-state

Let me know if that helps

That is indeed very helpful in understanding. I think that answers my question and will follow the GitHub issue. Maybe in the future there could be some local CLI options to set config entries in the /v2/local/target-state API. For now, I’ll just try and configure before first boot or manually update the API.