neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
eBus는 MQTT·mDNS·Homie 규격으로 가정 에너지 인프라 장치를 연결·조정하는 개방형 상호운용 프레임워크다
eBus (Electrification Bus) is an open interoperability framework enabling Home Energy Infrastructure devices to communicate and coordinate using MQTT, mDNS, and the Homie Convention.
개발 도구Rust · PythonGitHub @electrification-bus온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Rust SDK for eBus/Homie devices and controllers: MQTT transport, mDNS discovery
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Rust SDK for Electrification Bus (eBus): Homie 5 devices and controllers over MQTT, with mDNS broker discovery. It targets Linux single-board computers first and microcontrollers later.
Status: pre-alpha. The controller and device roles are implemented, and mDNS broker discovery and host advertisement run on the Avahi and mdns-sd backends.
Coming from python-sdk? doc/python-sdk.md maps its patterns to rust-sdk.
A controller watches the devices on a broker and sends them commands. It:README 전문 보기 ↗Rust SDK for Electrification Bus (eBus): Homie 5 devices and controllers over MQTT, with mDNS broker discovery. It targets Linux single-board computers first and microcontrollers later.
Status: pre-alpha. The controller and device roles are implemented, and mDNS broker discovery and host advertisement run on the Avahi and mdns-sd backends.
Coming from python-sdk? doc/python-sdk.md maps its patterns to rust-sdk.
A controller watches the devices on a broker and sends them commands. It:
ebus domain, the devices of one tree (a root and its children), or a single device;$description and checks every value against its property's datatype and format;$state and its effective state (a child of a lost root is lost);DeviceSynced), when its values do not arrive (DeviceStuck), and when it goes quiet after a reconnect (DeviceAbsent);/set and $broadcast, checking a /set payload against the property first;The application reads the latest state as cheap snapshots and receives changes as events.
A device publishes a tree of Homie devices (a root and its children) and takes commands for them. It:
$description from typed properties (property::<f64>, settable::<bool>, event::<i64>) and publishes init, the description, the values and ready, the root's $state last;/set to the application, which accepts it, accepts it with the value the device reached, or rejects it; $target properties report progress toward the target;lost state as the connection's last will;disconnected, by letting the will fire, or by removing every topic.A device and a controller can share one connection (ebus_rumqttc::pair).
A typical site has one MQTT broker, and every eBus host at the site connects to it. A host finds it in one of three ways:
The client sets which broker transports it accepts and its preference among them, by default the specification's order with _secure-mqtt._tcp first.
The host also advertises its own eBus services over mDNS. ebus-discovery-tokio finds the broker and advertises the host through avahi-daemon over D-Bus on Linux (its avahi feature), or on the pure-Rust mdns-sd backend (its mdns-sd feature) for Linux without Avahi and for macOS.
The crates are on crates.io. Most programs need only ebus-rumqttc, which re-exports the others it uses:
cargo add ebus-rumqttc
cargo add tokio --features macros,rt-multi-thread
Watch every device on a broker:
use ebus_rumqttc::ebus_homie_tokio::ebus_homie::controller::{Config, Event};
use ebus_rumqttc::ebus_homie_tokio::{ControllerOptions, Delivered};
use ebus_rumqttc::rumqttc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut mqtt = rumqttc::MqttOptions::new(ebus_rumqttc::controller_client_id(), "localhost", 1883);
// A `$description` can exceed rumqttc's 10 KiB default packet size.
mqtt.set_max_packet_size(4 << 20, 4 << 20);
let run = ebus_rumqttc::controller(mqtt, Config::wildcard(), ControllerOptions::default())?;
tokio::spawn(run.task.run());
let mut events = run.events;
while let Some(delivered) = events.recv().await {
if let Delivered::Event(Event::DeviceSynced { device, .. }) = delivered {
if let Some(view) = run.handle.device(&device) {
for (node, property, p) in view.properties() {
let value = p.value.as_ref().map(|v| &*v.raw);
println!("{device}/{node}/{property} = {value:?}");
}
}
}
}
Ok(())
}
Find the broker over mDNS instead, and find it again if its host gets a new address (ebus-discovery-tokio with its mdns-sd or avahi feature):
use std::time::Duration;
use ebus_discovery_tokio::ebus_discovery::BrokerConfig;
use ebus_discovery_tokio::{Mdns, find_broker, reresolve};
use ebus_rumqttc::ebus_homie_tokio::ControllerOptions;
use ebus_rumqttc::ebus_homie_tokio::ebus_homie::controller::Config;
use ebus_rumqttc::rumqttc::MqttOptions;
let mdns = Mdns::system().await?;
let cfg = BrokerConfig::default(); // discovery-only: the first broker advertised
let broker = find_broker(&mdns, cfg.clone()).await?;
let id = ebus_rumqttc::controller_client_id();
let options = |id: &str, host: &str, port: u16| {
let mut mqtt = MqttOptions::new(id, host, port);
mqtt.set_max_packet_size(4 << 20, 4 << 20);
mqtt
};
let mqtt = options(&id, &broker.connect_host(), broker.port);
let run = ebus_rumqttc::controller(mqtt, Config::wildcard(), ControllerOptions::default())?;
let task = run.task.reresolve(Box::new(move || {
let (mdns, cfg, broker, id) = (mdns.clone(), cfg.clone(), broker.clone(), id.clone());
Box::pin(async move {
let found = reresolve(&mdns, &broker, &cfg, Duration::from_secs(3)).await.ok()??;
Some(options(&id, &found.connect_host(), found.port))
})
}));
tokio::spawn(task.run());
The watch example prints every controller event. With neither EBUS_MQTT_HOST nor EBUS_MQTT_PORT set it finds the broker over mDNS; with either, it connects to that broker:
cargo run -p ebus-rumqttc --example watch -- wildcard
EBUS_MQTT_HOST=localhost cargo run -p ebus-rumqttc --example watch -- tree <root>
EBUS_MQTT_HOST=broker.local EBUS_MQTT_CA=ca.pem cargo run -p ebus-rumqttc --example watch --features rustls -- wildcard
Its source lists every setting, including EBUS_BROKER_MODE and EBUS_MDNS_BACKEND: crates/ebus-rumqttc/examples/watch.rs.
Publish a device:
use ebus_rumqttc::ebus_homie_tokio::device::{
DeviceOptions, DeviceSpec, NodeSpec, PropSpec, TreeBuilder, TreeConfig,
};
use ebus_rumqttc::rumqttc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mqtt = rumqttc::MqttOptions::new("my-device", "localhost", 1883);
let mut b = TreeBuilder::new(TreeConfig::default(), "my-device", DeviceSpec::default())?;
let node = b.node(b.root(), "sensor", NodeSpec::typed("example.sensor"))?;
let temperature = b.property::<f64>(node, "temperature", PropSpec::new().unit("°C"))?;
let mut led = b.settable::<bool>(node, "led", PropSpec::new())?;
temperature.set(21.5)?;
led.set(false)?;
let run = ebus_rumqttc::device(mqtt, b, DeviceOptions::default())?;
tokio::spawn(run.task.run());
while let Some(req) = led.next_set().await {
println!("led -> {}", req.value());
req.accept();
}
Ok(())
}
The device example adds a duration, an event and a clean shutdown on Ctrl-C, and takes the watch example's broker settings:
cargo run -p ebus-rumqttc --example device -- my-device
/set examplesThe tree-device example publishes a parent/child tree on one connection, as python-sdk's simple-tree-device does: a distribution enclosure with three circuits and a battery as children and a microgrid interconnect under the battery, built in one TreeBuilder so the root goes ready once for the tree. It prints each /set it accepts on circuit-3's switch/relay and the battery's control/reserve.
The set example pairs with it, as the --set option of python-sdk's simple-controller does with simple-tree-device: it waits for the device to sync, sends one /set and waits until the device reports the value. The controller's own checks refuse an unknown or non-settable property and an invalid value before anything is sent; the exit code tells these outcomes apart. Both take the watch example's broker settings:
cargo run -p ebus-rumqttc --example tree-device
cargo run -p ebus-rumqttc --example set -- circuit-3/switch/relay true
cargo run -p ebus-rumqttc --example set -- --root rust-tree bess-1/control/reserve 50
The simple-span-controller example, a port of python-sdk's simple-span-controller, reports whether a SPAN panel's home is islanded from the grid, watching the MID child's grid node and the enclosure's power-flows node. It finds the panel's broker over mDNS as the _secure-mqtt._tcp advertisement whose SRV target is span-<serial-number>.local, else connects to that host name after 5 s:
cargo run -p ebus-rumqttc --example simple-span-controller --features rustls -- <serial-number> [password]
Without a password argument it reads the panel's ebus_broker_password from SPAN_AUTH_FILE, else ~/.span-auth.json, the credential file of span_auth_utils in SPAN-API-Client-Docs. That file is optional, a convenience: its scripts/span-auth writes it (span-auth setup --wait registers with a panel, span-auth list shows the panels, span-auth default picks one). It verifies the broker against the panel's CA certificate, cached as <serial-number>.crt in SPAN_CA_CERT_DIR, else ~/.span-ca-certs, and downloaded from http://<host>/api/v2/certificate/ca when missing or expiring within a day; --insecure skips the check. Its source lists every option: crates/ebus-rumqttc/examples/simple-span-controller.rs.
A service can share its own MQTT client with the controller instead of opening a second connection: ebus_homie_tokio::attach_controller returns an inbox the client's reader feeds and a command stream the client sends. The host keeps its client version, TLS, last will and reconnect loop. The contract is in the ebus-homie-tokio crate docs.
A device can share the connection the same way (ebus_homie_tokio::device::attach_device, or attach_pair with a controller), provided the host installs the device's last will on it. The contract is in the device module docs.
| Crate | Role | no_std | Version |
|---|---|---|---|
ebus-rumqttc | The controller, the device, or both, with their own rumqttc 0.25 connection: TCP, or TLS with the rustls or native-tls feature; a reresolve hook finds a discovered broker again after its address changes | no | |
ebus-homie-tokio | Runs the controller and the device on tokio over a host-owned MQTT connection, with typed property handles | no | |
ebus-discovery-tokio | Finds the site's broker over mDNS, finds it again after an address change, and advertises the host's services, on tokio; Avahi backend under the avahi feature (Linux), mdns-sd backend under the mdns-sd feature | no | |
ebus-homie | Homie 5 protocol core: identifiers, topics, datatypes, $description, and the controller and device state machines. Performs no I/O | yes, with optional alloc | |
ebus-mqtt | MQTT vocabulary: messages and commands, topic filters and their ownership, and pairing two roles on one connection | yes, with optional alloc |
The core crates take std (the default), alloc, or neither as cargo features, and are driven by the caller: they receive messages and the current time and return the MQTT commands to send. The design, including subscription pacing, reconnect handling and the Homie state rules, is in doc/design.md.
Each v* tag on this repository publishes all six crates to crates.io at that version and creates the matching GitHub release, whose notes are that version's CHANGELOG section; CONTRIBUTING.md has the steps.
The Homie 5 convention and the eBus specification decide wire behavior. Where the spec leaves a choice open, rust-sdk follows python-sdk; where python-sdk deviates from the spec, rust-sdk follows the spec (python-sdk#110). Shared test vectors generated from python-sdk and python-service-discovery are in vectors/.
The minimum supported Rust version is 1.85. CI also tests 1.91.1 and the current stable release, and builds the core crates for thumbv7em-none-eabihf.
cargo test --workspace
The end-to-end tests start their own mosquitto and skip when it is not installed. Build commands, test settings and house style are in AGENTS.md; how to contribute is in CONTRIBUTING.md.
MIT; see LICENSE.
ebus-discovery | eBus DNS-SD contract: service types, TXT records, the advertisement model, and broker ranking and selection. Performs no I/O | yes, with optional alloc |