Python SDK#
The Python package is named enody. It wraps the Rust core with native PyO3
bindings and adds Python-friendly helpers for discovery, WiFi pairing, token
storage, firmware updates, JSON data, plotting, and tinygrad optimization. For
new host applications and CLI workflows, start with the Rust SDK.
Install#
pip install enody
Color science, plotting, and tinygrad optimization dependencies are included in the package for this branch; no separate science extra is required.
Discover a USB device#
import enody
env = enody.UsbEnvironment()
runtimes = env.runtimes()
if not runtimes:
raise SystemExit("No Enody devices found.")
runtime = runtimes[0]
host = runtime.host()
print(f"Host {host.identifier()} (v{host.version()})")
Traverse fixtures, sources, and emitters#
for fixture in host.fixtures():
print("fixture", fixture.identifier())
for source in fixture.sources():
print(" source", source.identifier())
for emitter in source.emitters():
data = emitter.spectral_data()
print(" emitter", emitter.identifier(), data.sample_count())
Display built-in modes#
from enody import Configuration, Flux
fixture = host.fixtures()[0]
fixture.display(Configuration.blackbody(4000), Flux.relative(0.8))
fixture.display(Configuration.chromatic(0.3127, 0.3290), Flux.relative(0.5))
Manual emitter control#
from enody import Configuration, Flux
source = fixture.sources()[0]
for emitter in source.emitters():
emitter.set_flux(Flux.relative(0.25))
fixture.display(Configuration.manual(), Flux.relative(1.0))
Work with sample data#
import enody.data
fixture = enody.data.sample_fixture()
source = enody.data.sample_source()
emitter = enody.data.sample_emitter()
print(fixture.identifier())
print(source.tensor().shape)
print(emitter.tensor().shape)
Sample data is device-shaped JSON loaded into the same Fixture, Source, and
Emitter classes used for connected devices. That makes offline experiments
look like hardware experiments.
Plot spectral data#
import enody.data
source = enody.data.sample_source()
source.plot_emitter_spectral_distributions(output="emitters.png", display=False)
source.plot_emitter_chromaticity_diagram(output="chromaticity.png", display=False)
WiFi discovery#
import enody
tokens = enody.TokenStore.load().tokens()
wifi = enody.WifiEnvironment(tokens)
for runtime in wifi.runtimes():
host = runtime.host()
print(host.identifier(), host.version())
Set up WiFi over USB#
import enody
runtime = enody.UsbEnvironment().runtimes()[0]
host = runtime.host()
for network in host.wifi_scan():
print(network.ssid(), network.rssi(), network.auth())
host.wifi_join("Studio WiFi", "network-password")
token = runtime.generate_token()
enody.TokenStore.save_token(token)
Generate a WiFi token#
import enody
token = enody.generate_wifi_token(
on_approval=lambda instruction: print(instruction),
save=True,
)
The helper discovers a token-generation candidate, requests device approval, verifies the token by reconnecting, and optionally saves it.
This pairing flow is the current integration primitive for saved-token clients. The exact Home Assistant integration surface is still TBD.
Update EP01#
import enody
for target in enody.UpdateTarget.discover():
print(target.identifier(), target.version())
target = enody.UpdateTarget.discover()[0]
versions = target.available_firmware()
target.update_device(versions[0])
Dependencies#
The package includes:
colour-sciencefor color science computations and plotting support.matplotlibfor generated spectral plots.tinygradfor tensor operations and optimization workflows.