JavaScript SDK#
The JavaScript package is named @enody/enody. It targets modern ESM
applications and provides the browser and Node.js SDK surface for EP01 discovery,
control, spectral data, optimization helpers, and firmware updates.
The package uses conditional exports:
- Browser builds use WebSerial.
- Node.js scripts use the Node serial backend.
- The same
@enody/enodyimport path works in both environments.
Install#
npm install @enody/enody
The package requires Node.js 18 or newer for Node-based tooling.
Discover and connect#
import { UsbEnvironment } from '@enody/enody';
const environment = new UsbEnvironment();
const runtimes = await environment.runtimes();
if (runtimes.length === 0) {
throw new Error('No Enody devices found.');
}
const runtime = runtimes[0];
const host = await runtime.host();
console.log(`Host ${host.identifier()} (v${host.versionString})`);
In browser apps, UsbEnvironment.runtimes() uses WebSerial. If the page has no
previously granted ports, the SDK can prompt the user to pick an EP01 serial
device. In Node.js, set ENODY_PORT when you need to target a specific serial
port.
Traverse fixtures, sources, and emitters#
const fixtures = await host.fixtures();
for (const fixture of fixtures) {
console.log('fixture', fixture.identifier());
for (const source of await fixture.sources()) {
console.log(' source', source.identifier());
for (const emitter of await source.emitters()) {
const data = await emitter.spectralData();
console.log(' emitter', emitter.identifier(), data.sampleCount());
}
}
}
Device-backed methods are asynchronous because they may issue protocol commands over USB serial.
Display built-in modes#
import { Configuration, Flux } from '@enody/enody';
const fixture = (await host.fixtures())[0];
await fixture.display(Configuration.blackbody(4000), Flux.relative(0.8));
await fixture.display(Configuration.chromatic(0.3127, 0.3290), Flux.relative(0.5));
Convenience helpers are available on fixtures:
await fixture.setCCT(4000, 0.8);
await fixture.setChromaticity(0.3127, 0.3290, 0.5);
await fixture.setManual(1.0);
Manual emitter control#
import { Configuration, Flux } from '@enody/enody';
const source = (await fixture.sources())[0];
for (const emitter of await source.emitters()) {
await emitter.setFlux(Flux.relative(0.25));
}
await fixture.display(Configuration.manual(), Flux.relative(1.0));
WiFi setup#
WiFi setup runs over an already trusted USB or WebSerial connection:
const networks = await host.wifiScan();
console.log(networks.map((network) => network.network?.ssid));
await host.wifiJoin('Studio WiFi', 'network-password');
Pass an empty password for open networks. Lower-level networkScan() and
networkJoin() helpers are also exported for non-WiFi network variants.
Runtime settings and presets#
The SDK can read and write public runtime settings, including the EP01 configuration preset setting used by host tooling:
import { Configuration } from '@enody/enody';
const presets = await runtime.configurationPresets();
presets.push(Configuration.blackbody(2700));
await runtime.setConfigurationPresets(presets);
Diagnostics#
Transport diagnostics are quiet by default. During hardware bring-up or support
sessions, pass a console-like logger or debug: true:
const environment = new UsbEnvironment({ logger: console });
Command timeouts reject with code: 'ENODY_COMMAND_TIMEOUT'. Device errors
include deviceError and command fields for application-level handling.
Work with sample data#
The package bundles the same fixture-shaped sample data used by the other SDKs:
import { sampleFixture, sampleSource, sampleEmitter } from '@enody/enody';
const fixture = sampleFixture();
const source = sampleSource();
const emitter = sampleEmitter();
console.log(fixture.identifier(), source.identifier(), emitter.identifier());
Optimization helpers#
The JavaScript SDK includes typed-array helpers for spectral matching, chromaticity work, blackbody spectra, plant band metrics, and optimizer loops.
import {
SpectralOptimizer,
cieXAction,
cieYAction,
cieZAction,
sampleSource,
} from '@enody/enody';
const source = sampleSource();
const emitters = await source.emitters();
const spdMatrix = new Float32Array(emitters.length * 401);
for (let i = 0; i < emitters.length; i += 1) {
const values = (await emitters[i].spectralData()).values();
spdMatrix.set(values, i * 401);
}
const optimizer = new SpectralOptimizer({
spdMatrix,
numEmitters: emitters.length,
cieX: new Float32Array(cieXAction()),
cieY: new Float32Array(cieYAction()),
cieZ: new Float32Array(cieZAction()),
});
optimizer.setTargetChromaticity(0.3127, 0.3290);
optimizer.step();
Update EP01#
import { UpdateTarget } from '@enody/enody';
const [target] = await UpdateTarget.discover();
const versions = await target.availableFirmware();
await target.updateDevice(versions[0], {
onLog: console.log,
verify: true,
});
By default, updater helpers fetch manifests from
https://firmware.enody.lighting. In local development, pass baseUrl to point
at a firmware proxy.
API overview#
Primary exports include:
UsbEnvironment,Runtime,Host,Fixture,Source,EmitterConfiguration,Flux,VersionNetwork,NetworkCredentials,WifiAuth,WifiNetworksampleFixture,sampleSource,sampleEmitterSpectralOptimizer,GPUCompute,computeChromaticity,computeSSIUpdateTarget,ESPFlasherCONFIGURATION_PRESETS_KEY,SENSOR_DATA_STREAMS_KEY