Local Development Setup¶
This is only needed if you are modifying iCEFARM specifically and want to use a debugger. The provided images are easier and faster to run, this setup should be avoided if possible.
Database Setup¶
iCEFARM uses postgres. Install postgres:
Start postgres: Create a database and user. Note that this can be configured using the command generator:sudo -u postgres psql
postgres=# CREATE ROLE {username} LOGIN PASSWORD '{password}';
postgres=# CREATE DATABASE {database} WITH OWNER = {username};
postgres=# GRANT ALL ON SCHEMA public TO {username}; #needed for flyway
/etc/postgresql/{version}/main/pg_hba.conf. For local use, the following entry can be added: Note that docker containers do not use local connections. To add an entry for another device: For non-local use, postgres needs to be configured to listen for other addresses. This can be done by changing listen_addresses in /etc/postgresql/{version}/main/postgresql.conf. Confirm that the login works: Now, the database connection string needs to be configured. This is a libpg connection string. This needs to be configured on all machines running the control or worker process: export ICEFARM_DATABASE='host={ip} port=5432 dbname={database name} user={username} password={password}
Flyway is used in order to apply migrations. Start by installing Flyway. Try running flyway:
Flyway ships with its own java runtime, which may be compiled for the wrong architecture. If you encounter an exec format error, ensure you have a separate java runtime installed and delete theflyway-{version}/jre/bin/java file. Now, Flyway needs to be configured. The configuration file is located at flyway-{version}/conf/flyway.toml. An example is provided by Flyway at flyway-{version}/conf/flyway.toml. In addition, here is a configuration that works with the project: [flyway]
locations = ["filesystem:migrations"]
cleanDisabled = false # optional
[environments.default]
url = "jdbc:postgresql://localhost:5432/{database}"
user = ""
password = ""
flyway.cleanDisabled setting is optional and enables the use of the flyway clean command. This essentially drops all of the objects in the database and is useful during development. In order to run the migrations: This can also be done with the database-rebuild vscode task. Note that in addition to running the migrations, it also runs clean beforehand. Building Firmware¶
If not already installed, install the pico-sdk and pico-ice-sdk. Make sure to run git submodule update --init in the pico-ice-sdk repo. Commands:
git clone https://github.com/tinyvision-ai-inc/pico-ice-sdk.git
cd pico-ice-sdk
git submodule update --init --recursive
git clone https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk
git submodule update --init --recursive
Create symlinks for the sdks in the firmware directory:
Run build.sh in this directory, or use the build-firmware task:
Configuration¶
For the control server:
| Environment Variable | Description | Default |
|---|---|---|
| ICEFARM_DATABASE | psycopg connection string | required |
| ICEFARM_CONTROL_PORT | Port to run on | 8080 |
Configuration for the worker can be done using environment variables or a toml file. Environment variables take precedence over the configuration file. Note that ICEFARM_DATABASE is not able to be provided through the configuration file. An example is provided. The worker has to run with sudo in order to upload firmware to devices. This means that the environment variables need to be passed along:
This may also be done with the -E flag, but this is not supported on all systems.| Environment Variable | Description | Default |
|---|---|---|
| ICEFARM_WORKER_CONFIG | Path to config file | None |
| ICEFARM_DATABASE | psycopg connection string | required |
| ICEFARM_WORKER_NAME | Name of the worker for identification purposes. Must be unique. | required |
| ICEFARM_CONTROL_SERVER | Url to control server | required |
| ICEFARM_DEFAULT | Path for Ready state firmware | required |
| ICEFARM_PULSE_COUNT | Path for PulseCount state firmware | required |
| ICEFARM_WORKER_LOGS | Log location | None - required if running with uvicorn |
| ICEFARM_SERVER_PORT | Port to host server on | 8081 |
| ICEFARM_VIRTUAL_IP | Ip for clients to reach worker with | First result from hostname -I |
| ICEFARM_VIRTUAL_PORT | Port for clients to reach worker with | 8081 |
Preparing Devices¶
The picos need to be plugged into the worker and running firmware that has tinyusb loaded. The rp2_hello_world example from the pico-ice-sdk works for this purpose.
Installing Module¶
Install iCEFARM module:
Debugging¶
Debug configurations are available in the launch.json. The worker requires sudo in order to upload firmware to the devices. Note that sudo changes the environment variables, so it is recommended to use a configuration file.
sudo ICEFARM_DATABASE="$ICEFARM_DATABASE" ICEFARM_WORKER_CONFIG="$ICEFARM_WORKER_CONFIG" .venv/bin/worker
Uvicorn¶
iCEFARM normally runs using uvicorn but can also use the flask debug server. There's not really a reason to run uvicorn in a development environment, as it does not allow for debugging, but otherwise should run identically. This mostly here for the sake of documenting how iCEFARM is started inside containers.
Uvicorn does not access environment variables unless they are contain a special prefix, which means the iCEFARM environment variables are not accessible by default. Variables can be passed with a .env file instead. The provided .uvicorn_env_bridge file passes iCEFARM related environment variables to uvicorn. As a result, configuration can be done through environment variables normally provided this environment file is included. Control:
uvicorn icefarm.control.app:run_uvicorn --env-file .uvicorn_env_bridge --factory --host 0.0.0.0 --port 8080
sudo ICEFARM_DATABASE="$ICEFARM_DATABASE" ICEFARM_WORKER_CONFIG=$ICEFARM_WORKER_CONFIG .venv/bin/uvicorn icefarm.worker.app:run_uvicorn --env-file .uvicorn_env_bridge --factory --host 0.0.0.0 --port 8081
Workflow¶
Vscode debug configurations are available for both the worker and control. There is also an assortment of vscode tasks. The task database-clear removes workers from the database and is useful to fix invalid worker/device states (this also causes all reservations/devices to be removed). This can also be done with psql -d "$ICEFARM_DATABASE" -c 'delete from worker;.
Testing¶
Tests assume that a newly launched worker and control instance are running with at least two devices available. If you do not have two devices, you can use worker/test.py. This applies patches to emulate device behavior without needing physical access. Running tests: pytest ./tests --url [control url] Note that if you do not specify the test directory, and have pico-sdk symlinks, pytest may pick up additional tests from dependencies. This applies patches to emulate device behavior without needing physical access. Tests are also automatically performed on main/development commits.