Advanced firmware
Extend Flova to Linux, Ethernet, custom boards, and application-owned setup flows.
Use the advanced paths when the standard ESP32 or ESP8266 composition does not match the product's hardware or service model.
Linux
Linux applications use FlovaLinux with a CMake package:
#include <FlovaLinux.h>
FlovaLinux device;
auto relay = FLOVA_DATASTREAM(device, bool, "relay");
int main() {
FLOVA_ON_WRITE(relay, applyRelay);
if (!device.begin()) return 1;
for (;;) device.run();
}The application owns the event loop and hardware integration. A service supervisor owns process startup, restart, and activation of a staged OTA image.
Custom boards
The portable core has four service boundaries:
flova::Device device(link, storage, clock, logger);
auto relay = device.datastream<bool>("relay");Implement flova::Link, flova::Storage, flova::Clock, and flova::Logger
for the board or gateway. Device::run() remains the point where queued
messages reach application hardware.
The transport can be a network connection or a gateway such as serial, CAN, BLE, or another bounded carrier. Keep the carrier adapter separate from the datastream and hardware logic.
Ethernet
ESP32 LAN8720 projects can use FlovaEsp32Ethernet. The application supplies
the PHY parameters and hardware handlers while the composition provides the
ESP32 network and Flova connection. A different Ethernet chip or TCP/IP stack
needs its own validated socket adapter.
Check the board schematic for boot pins, RMII reservations, power, DHCP, and certificate setup. A successful compile does not prove physical link, TLS, or hardware command acceptance.
Application-owned provisioning
An existing web server can keep its routes and network mode while the SDK adds the bounded provisioning handoff. BLE, serial, factory, and cellular setup paths can use the same handoff contract. The application remains responsible for authenticating and transporting its setup input.
Keep advanced integrations small: use the public facade first, inject a custom service only when the product actually owns that boundary.
Custom Arduino application boundary
The custom board facade is passive. It does not start a SoftAP, replace your web server, control GPIO, or reboot the board on its own. Your application chooses when to start Wi-Fi, which pins to use, and how to recover from a hardware fault.
The normal structure is:
FlovaEsp32 device;
auto sensor = FLOVA_DATASTREAM(device, float, "temperature");
void setup() {
startApplicationNetwork();
attachHardwareHandlers();
device.begin();
}
void loop() {
serviceApplicationHardware();
device.run(applicationNetworkReady());
}Keep the loop cooperative. A handler should update or queue application state, not wait for a second network request or perform a long blocking operation.
Status and lifecycle callbacks
Use the status listener when the product needs edge-triggered changes such as network ready, Link connected, runtime ready, or an error code. Keep the listener short and read detailed state from the facade after the callback.
For maintenance tools, expose bounded status fields such as network readiness, TLS readiness, runtime readiness, firmware target, and current lifecycle state. Do not expose tokens, secrets, full payloads, or private storage keys.
BLE and other setup channels
Provisioning transport is a firmware capability. A BLE, serial, Ethernet,
cellular, or factory adapter can decode its own input and pass a
ProvisioningHandoff to the client. The adapter owns pairing, framing, and
transport-specific timeouts. The SDK owns the bounded Flova handoff and runtime
session.
Keep the setup channel separate from normal telemetry. Once the handoff is durably accepted, release temporary setup resources before starting normal Link or MQTT work.
Hardware ownership
Use template mappings when the universal composition should apply standard inputs and outputs. Use application-owned handlers when the product needs custom debounce, calibration, interlocks, power sequencing, or board-specific pin rules.
Never assume that a valid cloud command is safe to apply directly. Check the current hardware state, limits, power conditions, and emergency policy before changing an output.
Custom integration checklist
- Choose universal or custom composition explicitly.
- Keep the public umbrella include in simple examples.
- Declare datastreams and settings before
begin(). - Provide storage that survives the reset behavior the product expects.
- Call
run()from the normal cooperative loop. - Keep callbacks bounded and hardware-aware.
- Verify provisioning, reconnect, template binding, command, report, and OTA separately.
- Keep wired recovery for the first image and failed updates.