Set a device configuration variable before boot

Hello - I was wondering if anyone knows if its possible to set a device configuration variable before first boot.

I have a device that will ship to users preloaded and pinned, without a wifi config - when the user applies their wifi config and the device appears in dashboard, I require it to already have a device configuration variable in its environment.

Currently, for example, I set the device name using balena os configure --initial-device-name on the image before I burn it to SD.

Is there a way to do similar for device specific configuration variables?

Hi Matt, as far as I know there is no method from the CLI currently, but I can see how this would be useful. It is a tricky one since as it currently works, any value found at first boot will be set by the supervisor as an override, potentially leading to mismatches between what you set app-wide and what the device sets if, for any reason, the wrong value is set onto the single device prior to boot. We’ll make sure this thread is updated whenever there is any news on the topic

2 Likes

Thanks for the reply!

Do you mean application environment variables, or host-specific config like dtparam on a Raspberry Pi?

@richbayliss I mean application environment variables - in the example I am talking about, its a one-time-use key that the device would use to provision with our cloud platform as soon as Wi-Fi is configured.

Is this key per-device or a common key which can be used multiple times? I ask because you could include it in the environment section of the compose file for the relevant service. There isn’t any way to make it device-specific as it comes directly from the release in the API. If you were to change the apps.json after preloading the image, then you could modify it there too, but that’s getting off the supported track, so to speak.

1 Like

This key is per-device.

Are you saying adding it to apps.json after a preload would work but be unsupported?

That said, I think I can flip to a common key for all devices as I am in a testing phase but its something I need to work out going forward, I think maybe a subtle architecture change would be easiest.

Hey Matt, I believe Rich was saying that setting your one-time-use key in the apps.json could achieve your goals but is not an officially supported feature so it could break in the future unexpectedly.

What if you try https://www.balena.io/docs/reference/balena-cli/#config-write-key-value which is basically the same as writing to apps.json but is supported. Alternatively since using SSL certs is a common technique for IOT identification maybe you could add a cert to each img after preloading. I saw https://www.balena.io/docs/reference/balena-cli/#-c---system-connection-system-connection which might work but check out what else is available from the CLI.

Check out https://www.balena.io/docs/reference/OS/configuration/ for information about the config.json if you plan to go that route.

1 Like

I asked some others if they of a better solution. We’ll get back to you if there is another way or if we plan to make this a first class feature rather then using these techniques.

1 Like

Thanks all for the replies, I’ll examine these routes!

@20k-ultra apologies if this is a dumb question…

I follow what you are saying but can only find config.json in Host OS at /mnt/boot , likewise with system-connections directory. Do I manually mount these for container access or are they already available somewhere?

In fact… I have just realised that BALENA_DEVICE_NAME_AT_INIT is not populated on a preloaded device either, and I am using that as a device identifier in quite a bit of my code, so I probably will need to access that config.json if possible.

I am running

balena os configure 2.2.1.img --app D_HB --initial-device-name <NAME>

and I can see the name being set in config.json, so, yeah, is it easy to access this?

Hey Matt,

I just wanted to clarify, are you asking if the containers in your application are able to read the variables configured in config.json?

Yes - pretty much - either the file itself so I can parse them or the variables stored in it.

As noted in the first post at top, I was originally looking to add device specific configuration. @20k-ultra suggested I used config write <key> <value> to add these to the config.json but I cannot see how my container accesses that file (or the values inside it).

Since directly reading config.json from a container is not currently possible, we discussed possible workarounds you can currently use.

The easiest I could think of but also the most insecure one would be to add the data you need to the hostname key in config.json. That is probably not a good idea, since it will be broadcasted to any nearby devices on the same network.

Another approach would be to define a UDEV rule to config.json (https://github.com/balena-os/meta-balena/#udevrules). For example you may attach the information you need as environment data to the Ethernet interface on the device, and then you can read this value from the container. If you are interested in this approach, but it is hard for you to implement as udev has steeper learning curve, please let us know so that we can provide you with an example.

A third more secure, but rather difficult approach would be to preregister each device with our balenaCloud. This will provide you with a device UUI that you can use to access your cloud’s API and retrieve the data you need remotely from there.

Please let us know if you have any questions.

Thanks,
Zahari

1 Like

Thanks for the reply @majorz - appreciate the response.

I will explore the second option, I have worked with udev some in the past so should be ok!

Its an interesting problem in general, I can mainly work around it when prototyping as I have max 20 devices but if scaling up somewhat, it would be good to have some sort of way to easily configure a device before it comes online!

would be to preregister each device with our balenaCloud

Expanding on this point, there are detailed instructions in this CLI masterclass section:

By knowing the device UUID in advance – even in advance of preloading, as you could generate the UUID alongside the one-time-use key of your own cloud platform – you might then be able to avoid storing the one-time-use key on the device in the first place. Just map the device UUID to the key in your own cloud platform database.

I have just realised that BALENA_DEVICE_NAME_AT_INIT is not populated on a preloaded device […]

I gather that supervisor v11.7.0 or later (shipped with balenaOS v2.52.4 or later) started taking into account the initialDeviceName field in config.json (as written by balena os configure). Could it be that you were testing it with an older version?

[…] and I am using that [BALENA_DEVICE_NAME_AT_INIT] as a device identifier in quite a bit of my code

As with the suggestion for replacing the one-time-use key with a pre-registered device UUID, you might also consider using the UUID as the device identifier instead of BALENA_DEVICE_NAME_AT_INIT. I gather that there is another env var, BALENA_DEVICE_UUID: Communicate outside the container - Balena Documentation

Talking of env vars, from some of your comments, it sounds like you’re already using application environment variables. Keep in mind that there are also device-specific environment variables that could be part of the solution: Variables - Balena Documentation
These device-specific env vars are not available before the first boot, though (as far as I know).

1 Like

I gather that supervisor v11.7.0 or later (shipped with balenaOS v2.52.4 or later) started taking into account the initialDeviceName field in config.json

I am using 11.12.4. From what I can see, I think it simply uses the initialDeviceName to set the device name in the cloud when it first connects, but before then it’s inaccessible.

That said, thanks for the pre-registration link and the UUID comments. I think I’m coming round to the fact that I will move to using uuid to manage in my cloud platform rather than device name.

Keep in mind that there are also device-specific environment variables

Yeah this is what we have been trying to use, but as we’ve discovered, theres no way to set these when preloading, before the device has connected to the balena cloud.

Hello,

Yeah this is what we have been trying to use, but as we’ve discovered, theres no way to set these when preloading, before the device has connected to the balena cloud.

If you pre-register a device, you should see it on the dashboard and be able to add environment variables via the dashboard or the cli.

Sorry for the confusion, you are right, the env vars set that way will only be visible on the device once it connects to balena cloud (as that’s where they are stored).

1 Like