Giter Club home page Giter Club logo

rs-matter's Issues

Cannot run example onoff_light in the no_std branch

Nightly Rust on Debian 10

nightly-x86_64-unknown-linux-gnu (overridden by '/home/chung/repos/matter-rs/rust-toolchain.toml')
rustc 1.70.0-nightly (478cbb42b 2023-03-28)
❯ RUST_BACKTRACE=1 cargo run --example onoff_light
    Finished dev [optimized + debuginfo] target(s) in 0.09s
     Running `target/debug/examples/onoff_light`
[2023-07-10T04:54:36Z INFO  onoff_light] Matter memory: mDNS=320, Matter=12080, Transport=39736
[2023-07-10T04:54:36Z INFO  onoff_light] Will use network interface enp3s0 with for mDNS
[2023-07-10T04:54:36Z INFO  onoff_light] Persisting from/to /tmp/matter-iot
[2023-07-10T04:54:36Z INFO  matter::transport::core] Starting Matter transport
[2023-07-10T04:54:36Z INFO  matter::pairing::code] Pairing Code:
[2023-07-10T04:54:36Z INFO  matter::pairing::qr] QR Code: 
[2023-07-10T04:54:36Z INFO  matter::pairing::qr] 
[2023-07-10T04:54:36Z INFO  matter::transport::core] Comissioning started
[2023-07-10T04:54:36Z INFO  matter::transport::udp::smol_udp] Listening on [::]:5540
Error: Error::StdIoError {
   0: matter::error::Error::new
             at ./matter/src/error.rs:93:24
   1: <matter::error::Error as core::convert::From<std::io::error::Error>>::from
             at ./matter/src/error.rs:141:9
   2: <core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/result.rs:2067:27
   3: matter::transport::udp::smol_udp::UdpListener::new::{{closure}}
             at ./matter/src/transport/udp.rs:39:25
   4: matter::mdns::builtin::MdnsRunner::run_udp::{{closure}}
             at ./matter/src/mdns/builtin.rs:124:76
   5: onoff_light::run::{{closure}}
             at ./matter/../examples/onoff_light/src/main.rs:223:63
   6: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/future/future.rs:125:9
   7: <&mut F as core::future::future::Future>::poll
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/future/future.rs:113:9
   8: <embassy_futures::select::Select<A,B> as core::future::future::Future>::poll
             at /home/chung/.cargo/registry/src/index.crates.io-6f17d22bba15001f/embassy-futures-0.1.0/src/select.rs:55:33
   9: onoff_light::run::{{closure}}
             at ./matter/../examples/onoff_light/src/main.rs:225:71
  10: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/future/future.rs:125:9
  11: <&mut F as core::future::future::Future>::poll
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/future/future.rs:113:9
  12: async_io::driver::block_on
             at /home/chung/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-io-1.12.0/src/driver.rs:146:33
  13: onoff_light::run
             at ./matter/../examples/onoff_light/src/main.rs:228:5
  14: core::ops::function::FnOnce::call_once
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/ops/function.rs:250:5
  15: std::sys_common::backtrace::__rust_begin_short_backtrace
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/sys_common/backtrace.rs:134:18
  16: std::thread::Builder::spawn_unchecked_::{{closure}}::{{closure}}
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/thread/mod.rs:525:17
  17: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/panic/unwind_safe.rs:271:9
  18: std::panicking::try::do_call
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/panicking.rs:485:40
  19: std::panicking::try
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/panicking.rs:449:19
  20: std::panic::catch_unwind
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/panic.rs:140:14
  21: std::thread::Builder::spawn_unchecked_::{{closure}}
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/thread/mod.rs:524:30
  22: core::ops::function::FnOnce::call_once{{vtable.shim}}
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/core/src/ops/function.rs:250:5
  23: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/alloc/src/boxed.rs:1988:9
  24: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/alloc/src/boxed.rs:1988:9
  25: std::sys::unix::thread::Thread::new::thread_start
             at /rustc/478cbb42b730ba4739351b72ce2aa928e78e2f81/library/std/src/sys/unix/thread.rs:108:17
  26: start_thread
  27: __clone
}

[TESTS] End-to-end tests

I have the not so comfy feeling, that the tests covering rs-matter are just not enough, and so we are prone to regressions as we develop it over time. (Guilty as charged here, btw.)

Unit tests are one thing, but they can only go so far.
Also, the higher up you climb the stack, the more difficult it becomes to create and maintain such ones.

Though - I must say - the way I've influenced the existing semi-unit-tests/semi-e2e-tests that originally tested the Interaction/Data Layer is that they are currently more of an e2e test suite - as they are exercising aspects of the transport layer too - than what they were originally - tests bound to the Data layer only. So we might evolve this "framework" too, but writing the test cases themselves is super-boring, ergo, I'm looking at reusing someone else's test cases.

Regardless, and without digressing any further, the question:
@kedars, @andreilitvin: Are there / is there an e2e test framework in the C++ SDK that we can somehow extract and re-use in the context of rs-matter?

I'm imagining - roughly speaking - a bunch of automation tests - likely in the form of shell or Python scripts exercising the chip-tool command line and executed against an up-and-running version of the C++ SDK (which we should be able to replace with an up-and-running rs-matter stack).

So, does such an animal exist, in there? Can you point me to it?

[MDNS] Remove all on-stack buffers from our built-in mDNS

Turns out the domain library is versatile enough so that we can completely get rid of on-stack buffers like this one.

Ongoing work in this branch of edge-mdns.
If successful (which seems more and more likely now that I can serialize even TXT records without extra buffers), I'll merge back bits and pieces from this new implementation into rs-matter.

cargo build fails

image
Hi guys, I am using a custom dev baord running ubuntu 20.04 and tried to build this repo. But I receive the above error.
I tried to change the env_logger version but still receive the same error.
Please guide me.

Thanks

Come up with and then apply a more consistent naming convention

Where I think our current naming convention (primarily for types and module names, but perhaps not only) is inconsistent:

  • Sometimes we abbreviate, sometimes we don't. Not the end of the world, if it wasn't the case that some types and modules contain abbreviated words and very long un-abbreviated words. Examples:
    • module sdm (System Data Model): ok, but then we have un-abbreviated system_model and interaction_model
    • ethernet_nw_diagnostics: why abbreviate network to nw when diagnostics and ethernet are not abbreviated
    • nw_commissioning - ditto
  • Sometimes - maybe - we abbreviate a bit too much:
    • EndptId - we have saved only 2 characters compared to - say - EndpointId, and the word endpoint is not abbreviated anywhere else, nor is ClusterId abbreviated which is only 1 char shorter
    • We are not always consistent: ethernet_nw_diagnostics, but then EthNwDiagCluster. If we abbreviate the cluster name, perhaps we should abbreviate the module name as well, i.e. eth_nw_diag?

The list can continue, and probably the first step would be to identify a set of names that need to be refactor-renamed, as well as a justification why.

Ideally, we should be consistent in our abbreviations, even if we won't overdo it by building a glossary (but consulting the internet and then using common abbreviations, like here and here should be mandatory).

  • I.e. ideally "ethernet" should be abbreviated everywhere to "eth" or not abbreviated everywhere. There should be few if any exceptions to this rule.
  • I.e. ideally we should use the same abbreviation for a concrete term (if abbreviated at all) everywhere

I don't think we need to waterfallish-ly come up with a long list of identifiers for renaming and only then open a giant PR for that. Yet we should probably follow at least these two rules:

  • A rename PR should only be a rename PR and nothing else. No change in the behavior of the code
  • Until something is renamed (abbreviated or not), we should use the most popular name for the thing in the code, regardless whether we like it, so that the code looks mostly consistent

IPv6-specific "Host is unreachable" error that exits the matter runtime

Environment
Chip: ESP32-C3-MINI-1
Hardware: ESP32-C3-DevKitM-1
Platform: esp-idf (Rust std)

Problem
I likely have something misconfigured on my network causing IPv6 broadcasts to yield a surprising "Host is unreachable" error, however the more important issue is that the way the master future is structured in my example (and onoff_light) causes the entire Matter runtime to effectively shutdown and not automatically restart.

An abridged version of the log shows the issue:

I (7607) rs_matter::transport::core: Comissioning started
I (7617) rs_matter::transport::core: Creating queue for 1 exchanges
I (7617) rs_matter::transport::core: Creating 8 handlers
I (7627) rs_matter::transport::core: Handlers size: 9992
I (7637) rs_matter::transport::core: Transport: waiting for incoming packets
I (7647) rs_matter::transport::udp::async_io: Listening on [::]:5353
I (7647) rs_matter::transport::udp::async_io: Joined IPV6 multicast ff02::fb/2
I (7657) rs_matter::transport::udp::async_io: Joined IP multicast 224.0.0.251/192.168.86.32
I (7667) rs_matter::mdns::builtin: Broadcasting mDNS entry to 224.0.0.251:5353
I (7687) rs_matter::mdns::builtin: Broadcasting mDNS entry to ff02::fb:5353
W (7697) rs_matter::transport::udp::async_io: Error on the network: Os { code: 118, kind: HostUnreachable, message: "Host is unreachable" }
Error: Error::Network

The last line in particular appears to be coming from the master future in the onoff light example: https://github.com/project-chip/rs-matter/blob/main/examples/onoff_light/src/main.rs#L165

This is "fixed" by just disabling IPv6 for me, but I do think this highlights some bigger issues with the error handling robustness inside the runtime. In particular I'd expect that the IPv4 and IPv6 behaviour be separated into separate futures that can error out independently and that one reaching a terminal state wouldn't negatively impact the other. Further I think some measure of error handling policy is appropriate (Host is unreachable seems like it should probably be retryable for example). I could take a crack at a patch but I do worry based on the current state of the code that it might be a bit intrusive. Any guidance from the maintainers would be greatly appreciated before getting started!

Thanks again for this awesome project, it's renewed my interest big time in IoT :)

Error when trying to add device to Google Home

I got the onoff_light example working on my ESP32-C3-DevKitM-1 (after some tweaking to remove IPv6 support, see #100), but I'm having a couple of issues getting the device to appear and be controllable from Google Home.

First, trying to scan the QR code doesn't work and immediately produces an error as soon as I move my phone camera nearby to the QR code (see [1] below). If I switch to manually entering the pairing code things progress and I see a lot of log spamming from the device (which all looks successful generally and nothing appears to timeout).

Second, after seemingly trying to pair with the new device and bring it into Google Home I'm presented with [2] and I can't do anything to try again or proceed, only back out.

Full logs from boot-up attached here: https://gist.github.com/jasta/ed826fed780f9cc6109499b3fbe4f852

Is this expected? If no, anything I can try to do to debug and figure out what's wrong? I was able to successfully add a device using the main C++ matter repository and the all-clusters-app example and it seemingly worked well even to control the device. This was however a few months ago with a beta of Google Home.

[1]
[2]

EDIT: Apologies I just realized the screenshots are in Spanish. [1] is saying that it's not a matter QR code, and [2] is saying that the device isn't certified for use with Matter.

Add pipeline for upload matter-rs crates to crates.io

I hope this message finds you well. I am reaching out to kindly request the upload of the matter-rs packages to crates.io in order to facilitate their usage in our projects.

We have been eagerly following the development of matter-rs and are impressed by its features and potential benefits for our projects. However, we have encountered difficulty in accessing the crates through crates.io, which is the primary repository for Rust packages.

To ensure seamless integration and compatibility within our projects, we kindly request that you consider publishing the matter-rs packages to crates.io. This will enable us and other members of the Rust community to easily include and utilize this valuable resource in our development workflows.

We understand the effort and dedication required to maintain and distribute crates, and we truly appreciate your contribution to the Rust ecosystem. By making the matter-rs packages available on crates.io, you would greatly enhance their accessibility and encourage wider adoption among developers.

Thank you for your time and consideration. We look forward to your positive response and eagerly anticipate the availability of the matter-rs packages on crates.io.

Pairing with Apple Home fails

After implementing PR #7 the pairing of the onoff_light can be started from Apple Home using the QR code.
It prompts the user that the device is uncertified. After confirming the dialog, the process continues.
Ultimately the onboarding fails, indicating that the accessory could not be paired.
In the logs there is no error, or an indication as to what went wrong:

2023-01-11-matter_rs_log-1.log

[Documentation] Document existing APIs which are already in-place

The following older sections of the code (pre 2024) need a lot more documentation:

  • IM layer (partially). Stuff like the handlers, objects, encoding module and others
  • SC layer - all of it
  • Crypto code
  • QR code
  • ACLs
  • Fabrics
  • Maybe more?
  • Sessions code in the transport layer, and possibly packet parsing / creation

I suggest we just add it over time. I can do IM layer and Sessions code as in the meantime my code contributions there prevail over the original code, and there, the complexity is a bit bigger.

I'll start opening PRs with this.

argument type of `print_pairing_code_and_qr()`

Hello there,

I have a suggestion regarding the print_pairing_code_and_qr() function. Currently, it accepts comm_data: &CommissioningData as an argument. However, according to section 5.1 of the Matter-1.0-Core-Specification, both MPC and QR Code require a passcode.

The CommissioningData has either VerifierOption::Password or VerifierOption::Verifier. In my understanding, passing VerifierOption::Verifier instead of VerifierOption::Password as an argument to print_pairing_code_and_qr() will result in a runtime error.

To avoid this issue, I recommend passing VerifierOption::Password as the argument to print_pairing_code_and_qr() instead.

[Examples] Remove code duplication

The existing two examples (onoff_light and the upcoming onoff_light_bt) have a lot of code duplication which will only grow if more examples are coming:

  • Device attestation code
    • Move to a shared common/dev_att.rs file
    • Possibly use include_bytes! rather than encoding the certificates in static Rust slices
  • Detection of network configuration (ipv4 and ipv6)
    • Move to a common utility?
  • Running mDNS, persister and others
    • Move to a common utility, if possible?

On the other hand, examples are supposed to be straightforward, even if that means a bit of a code duplication. So beyond moving the device attestation to a common file (which is non-controversial), we have to see what else makes sense to unify.

Examples also tend to be very verbose currently, and that's because rs-matter is more of a toolkit rather than a ready-to-use solution.

Perhaps we need something like rs-matter-stack in future as a sibling crate to the existing ones? For one, it tends to produce much smaller examples, as that crate is more oppinionated.

PAKE State Machine Robustness

  • Generate appropriate error codes as per the spec
  • Overall robustness/state machine for state cleanup during error scenarios

Occasional panic in crypto_mbedtls.rs

During pairing with Apple Home a panic was triggered in crypto_mbedtls.rs.
This happened only once and I was unable to reproduce the issue so far. Will update this issue if it happens again.

[2023-01-15T10:52:02Z INFO  matter::data_model::sdm::noc] Handling Command CSRRequest
[2023-01-15T10:52:02Z INFO  matter::data_model::sdm::noc] Received CSR Nonce:OctetStr([52, 226, 46, 191, 82, 255, 246, 250, 115, 248, 188, 209, 33, 137, 211, 219, 31, 19, 195, 59, 234, 232, 71, 18, 40, 161, 131, 213, 218, 57, 218, 134])
thread 'main' panicked at 'attempt to subtract with overflow', src/crypto/crypto_mbedtls.rs:290:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

[BUG] Light On Off Example Crashing [M1][no_std]

Branch : no_std
Platform : Darwin arm64 (M1 Mac Book Pro)

When trying to run the example on M1 Mac I get the following error.
I might have time to investigate this later in the meantime I'm leaving this here:

matter-rs % bash -c "RUST_BACKTRACE=1 cargo run --example onoff_light"
warning: Patch `polling v2.2.0 (https://github.com/esp-rs-compat/polling#0a016089)` was not used in the crate graph.
Patch `smol v1.2.5 (https://github.com/esp-rs-compat/smol#15918c3c)` was not used in the crate graph.
Patch `socket2 v0.4.5 (https://github.com/esp-rs-compat/socket2#afeb7231)` was not used in the crate graph.
Check that the patched package version and available features are compatible
with the dependency requirements. If the patch has a different version from
what is locked in the Cargo.lock file, run `cargo update` to use the new
version. This may also occur with an optional dependency that is not enabled.
    Finished dev [optimized + debuginfo] target(s) in 0.26s
     Running `target/debug/examples/onoff_light`
[2023-06-30T07:59:59Z INFO  onoff_light] Matter memory: mDNS=320, Matter=12080, Transport=39736
[2023-06-30T07:59:59Z INFO  onoff_light] Will use network interface en0 with 10.5.221.91/fe80::1ca2:f0c3:35b1:2a5d for mDNS
[2023-06-30T07:59:59Z INFO  onoff_light] Persisting from/to /var/folders/zf/jdpvrr2n04v_pgcx1_hjkn300000gn/T/matter-iot
[2023-06-30T07:59:59Z INFO  matter::transport::core] Starting Matter transport
[2023-06-30T07:59:59Z INFO  matter::pairing::code] Pairing Code: 0087-6800-071
[2023-06-30T07:59:59Z INFO  matter::pairing::qr] QR Code: MT:Y.K90Q1212Z6Q66D33P084L90Z.I332SQ43I15T0
[2023-06-30T07:59:59Z INFO  matter::pairing::qr] 
    █████████████████████████████████████
    █████████████████████████████████████
    ████ ▄▄▄▄▄ █▀██ █▀▀▄ █  ▄█ ▄▄▄▄▄ ████
    ████ █   █ █ ▀█▀▄▄█▄▀▄ ▄▄█ █   █ ████
    ████ █▄▄▄█ ██▄ █ ██ ▄ ▀▀▀█ █▄▄▄█ ████
    ████▄▄▄▄▄▄▄█ █▄█ █ ▀ █ █ █▄▄▄▄▄▄▄████
    ████▄▀▀▀▀▀▄█▄▀█ █▀██ ▀ ██▄ ▀▀ ▄ ▀████
    ████▀█  ▀▀▄ ▄▄▀▄▄ ▄▄▄█▀█▄██▄ ▄▀▀▄████
    ████▀ ▀ █▄▄▀▄▀▀█ ▄█▄ ▀ ▀█ ██   ▀▀████
    ████ █  █▀▄█  ▄▀▀██▀█▀█ ▀▄ ▀ ██ ▄████
    ████▀▄▄█▄ ▄ ▀ ▀ ▄▀▀█▄▀█▀▄▄▀▄▄▀ ▀ ████
    ████ ▄▀█▄█▄ ▄█▀▄█▀█▄█▄▄▄█▄█  ▄  ▀████
    ████▄█▄██▄▄█▀▀   █ ▄█▀█▄ ▄▄▄ ▄▀▀▄████
    ████ ▄▄▄▄▄ ██▀█ ▄█▀▀▀▀ ▀ █▄█ ▄▄ ▄████
    ████ █   █ ██ ▀█▄▄ █▄▀██▄▄▄ ▄▄ ▀▄████
    ████ █▄▄▄█ ██ ▀▀ ▄█▄▀▄▀█▀▄▀ ▀  ▄█████
    ████▄▄▄▄▄▄▄█▄█████▄▄██▄▄█▄██▄█▄▄█████
    █████████████████████████████████████
    ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
[2023-06-30T07:59:59Z INFO  matter::transport::core] Comissioning started
[2023-06-30T07:59:59Z INFO  matter::transport::udp::smol_udp] Listening on [::]:5540
Error: Error::StdIoError {
   0: std::backtrace::Backtrace::create
   1: matter::error::Error::new
             at ./matter/src/error.rs:93:24
   2: <matter::error::Error as core::convert::From<std::io::error::Error>>::from
             at ./matter/src/error.rs:141:9
   3: <core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/result.rs:2002:27
   4: matter::transport::udp::smol_udp::UdpListener::new::{{closure}}
             at ./matter/src/transport/udp.rs:39:25
   5: matter::mdns::builtin::MdnsRunner::run_udp::{{closure}}
             at ./matter/src/mdns/builtin.rs:124:76
   6: onoff_light::run::{{closure}}
             at ./matter/../examples/onoff_light/src/main.rs:223:63
   7: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/future/future.rs:125:9
   8: <&mut F as core::future::future::Future>::poll
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/future/future.rs:113:9
   9: <embassy_futures::select::Select<A,B> as core::future::future::Future>::poll
             at /Users/nikolasvonlonski/.cargo/registry/src/index.crates.io-6f17d22bba15001f/embassy-futures-0.1.0/src/select.rs:55:33
  10: onoff_light::run::{{closure}}
             at ./matter/../examples/onoff_light/src/main.rs:225:71
  11: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/future/future.rs:125:9
  12: <&mut F as core::future::future::Future>::poll
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/future/future.rs:113:9
  13: async_io::driver::block_on
             at /Users/nikolasvonlonski/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-io-1.12.0/src/driver.rs:146:33
  14: onoff_light::run
             at ./matter/../examples/onoff_light/src/main.rs:228:5
  15: core::ops::function::FnOnce::call_once
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/ops/function.rs:250:5
  16: std::sys_common::backtrace::__rust_begin_short_backtrace
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/sys_common/backtrace.rs:134:18
  17: std::thread::Builder::spawn_unchecked_::{{closure}}::{{closure}}
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/thread/mod.rs:526:17
  18: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/panic/unwind_safe.rs:271:9
  19: std::panicking::try::do_call
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/panicking.rs:485:40
  20: std::panicking::try
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/panicking.rs:449:19
  21: std::panic::catch_unwind
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/panic.rs:140:14
  22: std::thread::Builder::spawn_unchecked_::{{closure}}
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/std/src/thread/mod.rs:525:30
  23: core::ops::function::FnOnce::call_once{{vtable.shim}}
             at /private/tmp/rust-20230613-7622-103lepv/rustc-1.70.0-src/library/core/src/ops/function.rs:250:5
  24: std::sys::unix::thread::Thread::new::thread_start
  25: __pthread_joiner_wake
}

Can't establish CASE, rs-matter unable to verify ICAC certificate that's missing subject key ID extension

I'm trying to commission a test device utilizing this crate with a SmartThings Hub. It's currently failing to establish CASE, and I've tracked it down to the verification of the initiator ICAC sent by the controller to the device.

This is what I could find in the spec about validating the Sigma3 message:

The responder SHALL verify that the NOC in TBEData3.responderNOC and the ICAC in TBEData3.responderICAC fulfill the following constraints:
a. The Fabric ID SHALL match the Fabric ID matched during processing of the Destination
Identifier after receiving Sigma1.
b. If an ICAC is present, and it contains a Fabric ID in its subject, then it SHALL match the Fab
ricID in the NOC leaf certificate.
c. The certificate chain SHALL chain back to the Trusted Root CA Certificate TrustedRCAC whose
public key was matched during processing of the Destination Identifier after receiving Sig
ma1.
d. All the elements in the certificate chain SHALL respect the Matter Certificate DN Encoding
Rules, including range checks for identifiers such as Fabric ID and Node ID.

The only validation specified for ICAC is that the fabric ID matches that of the NOC leaf certificate, which appears to be done here:

if let Ok(fid) = icac.get_fabric_id() {

I've verified that that is occurring with log statements. However, just below that, it is failing to add the cert to the verifier. From adding my own logs, I've determined that it is failing here:

pub fn is_authority(&self, their: &Cert) -> Result<bool, Error> {

The ICAC has no subject key ID extension, so the function returns an error. Given that the ST Hub is Matter certified I suspect that something is overly strict with this certificate verification. However, this is out of my realm of expertise.

I also logged the ICAC following the parsing from TLV in case that's helpful:

Cert { 
    serial_no: OctetStr([67, 38, 73, 198, 26, 31, 20, 101, 57, 46, 16, 143, 77, 160, 128, 161]), 
    sign_algo: 1, 
    issuer: DistNames { 
        dn: [(20, Uint(15512483513290480383))] 
    }, 
    not_before: 718486395, 
    not_after: 874187555, 
    subject: DistNames { 
        dn: [(19, Uint(14440658877384716286))] 
    }, 
    pubkey_algo: 1, 
    ec_curve_id: 1, 
    pubkey: OctetStr([4, 88, 188, 13, 87, 50, 3, 213, 248, 182, 12, 240, 164, 220, 127, 150, 65, 81, 244, 125, 24, 48, 203, 83, 111, 133, 175, 182, 10, 40, 80, 147, 28, 39, 121, 183, 61, 159, 178, 231, 133, 75, 189, 143, 136, 191, 254, 115, 228, 186, 129, 56, 137, 213, 177, 13, 46, 97, 202, 95, 41, 5, 16, 24, 228]), 
    extensions: Extensions { 
        basic_const: Some(BasicConstraints { is_ca: true, path: Some(0) }), 
        key_usage: None, 
        ext_key_usage: None, 
        subj_key_id: None, 
        auth_key_id: Some(OctetStr([243, 119, 107, 152, 3, 212, 205, 76, 85, 38, 158, 240, 27, 213, 11, 235, 33, 21, 38, 5])), 
        future_extensions: None 
    }, 
    signature: OctetStr([70, 43, 150, 195, 194, 170, 43, 125, 91, 213, 210, 221, 175, 131, 131, 85, 22, 247, 213, 18, 101, 189, 30, 134, 20, 226, 217, 145, 41, 225, 181, 150, 28, 200, 52, 237, 218, 195, 144, 209, 205, 73, 88, 114, 139, 216, 85, 170, 63, 238, 164, 69, 35, 69, 39, 87, 211, 234, 57, 98, 19, 43, 13, 0]) 
}

[Copyright] Update all copyright headers

We need to update all copyright headers as they currently say "Copyright 2020 - 2022..." and 2022 is in the past.

Is the CSA alliance having any prescriptions here? If not:

@andreilitvin mentioned the C++ SDK has a policy to put newer copyright only in the files they newly add (or change?) BUT I do not understand this policy at all.

Copyright headers of all files - old or new always need to be up to date. Always. Not a lawyer, but pretty sure about that. Otherwise it would look as if the copyright of the old files had expired, which is just not the case.

Two options I can think of:

  • Periodically update (with regexp) the copyright headers by bumping up the ending year. I.e. it would become "Copyright 2020 - 2024" if we do it now.
  • (I prefer this) Change all headers to read "Copyright since 2020 - ", i.e. remove the ending year.

What to do with the beginning year? Also two options:

  • Option 1: I suggest - we just use the year when the new file "lands" in the repo. And don't touch it afterwards. I don't feel like going through all of them and changing the beginning year though, as that is a lot of pointless work
  • Option 2: Remove the beginning year as well. Why do we need it? It is anyway a copyright since the very existence of the file and until eternity (or until we decide otherwise). So the final message should just be "Copyright (c) Project Chip Authors"

Keep the IP address of the subscribing peer node in subscriptions?

Copying the part of #181 which is still unresolved here, to keep the discussion open:

Apple Matter is a bit weird. Putting aside the fact that we are commissioned into two fabrics, the other weird thing that happens is that once we are commissioned in the second fabric, they are communicating with us on behalf of TWO different IP addresses, which - however - do represent the same node+fabric ID?!

  • IP Address 1 (in my case): fe80::8d7:cf23:8b0b:f715%2 - in fact this guy has two different nodes, one on fabric 1, and another on fabric 2 - see our session dump below
  • IP Address 2: fe80::416:93dd:216a:d50a%2 - this guy has the only one node on fabric 1 (or so we know), but its node on Fabric 1 is the same as the node of the previous IP!

And now the real weird part: we receive a subscription request from IP Address 2 and this all goes well.
But when the time comes to report on that subscription in some seconds / minutes and initiate a new exchange, it just so happens that we select an existing session for "IP Address 1" instead, because we are just looking for a session matching the fabric index (=1) and the node ID. And since the first address also has created sessions to us on behalf of fabric 1, we just happen to pick a session for IP Address 1, even if the subscription came from IP Address 2.

... and get "Invalid Subscription" from the other peer.

Now, if we pick a session based on fabric index + peer node ID + remote address, then we select a session with "IP Address 2" (the address from where the subscription came) and all is well!

So @kedars what do you think is going on? Shall I just also keep the IP address in the subscription data and do a match by that address too? This works (confirmed) but sounds a bit weird. Am I missing something in the spec?

Session dump:

Sessions for IP Address 1:
=============================================

(Skip this block, it contains non-CASE sessions, not interesting):
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(1088638830675445622), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 9017568, mode: PlainText, ts: 1717612457.779132481s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(0), local_nodeid: 0, local: 1, remote: 8566, msg_ctr: 44517232, mode: Pase(NotExpected), ts: 1717612462.458154527s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(9297024357880017542), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 87475376, mode: PlainText, ts: 1717612462.78951294s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(17849542785653146437), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 35224863, mode: PlainText, ts: 1717612493.671745767s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(1088638830675445622), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 9017568, mode: PlainText, ts: 1717612457.779132481s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(0), local_nodeid: 0, local: 1, remote: 8566, msg_ctr: 44517232, mode: Pase(NotExpected), ts: 1717612462.458154527s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(9297024357880017542), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 87475376, mode: PlainText, ts: 1717612462.78951294s
Session: fb_idx: None,    peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(17849542785653146437), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 35224863, mode: PlainText, ts: 1717612493.671745767s

!!! This block is interesting:
Session: fb_idx: Some(1), peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(864992019), local_nodeid: 1121512030, local: 2, remote: 8567, msg_ctr: 198121502, mode: Case(CaseDetails { fab_idx: 1, cat_ids: [0, 0, 0] }), ts: 1717612496.261807843s
Session: fb_idx: Some(2), peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(3725013030), local_nodeid: 4012158658, local: 3, remote: 8568, msg_ctr: 254531801, mode: Case(CaseDetails { fab_idx: 2, cat_ids: [0, 0, 0] }), ts: 1717612494.724025958s
Session: fb_idx: Some(1), peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(864992019), local_nodeid: 1121512030, local: 2, remote: 8567, msg_ctr: 198121502, mode: Case(CaseDetails { fab_idx: 1, cat_ids: [0, 0, 0] }), ts: 1717612500.816538095s
Session: fb_idx: Some(2), peer: [fe80::8d7:cf23:8b0b:f715%2]:51398, peer_nodeid: Some(3725013030), local_nodeid: 4012158658, local: 3, remote: 8568, msg_ctr: 254531801, mode: Case(CaseDetails { fab_idx: 2, cat_ids: [0, 0, 0] }), ts: 1717612494.724025958s


Sessions for IP Address 2:
=============================================
(Skip this block, it contains non-CASE sessions, not interesting):
Session: fb_idx: None,    peer: [fe80::416:93dd:216a:d50a%2]:65218, peer_nodeid: Some(1162526195568380034), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 84020839, mode: PlainText, ts: 1717612496.321803477s
Session: fb_idx: None,    peer: [fe80::416:93dd:216a:d50a%2]:65218, peer_nodeid: Some(1162526195568380034), local_nodeid: 0, local: 0, remote: 0, msg_ctr: 84020839, mode: PlainText, ts: 1717612496.321803477s

!!! This block is interesting: see - fb_idx = 1 and peer_nodeid = 864992019 which is also present for Address 1?!
Session: fb_idx: Some(1), peer: [fe80::416:93dd:216a:d50a%2]:65218, peer_nodeid: Some(864992019), local_nodeid: 1121512030, local: 4, remote: 48265, msg_ctr: 226861159, mode: Case(CaseDetails { fab_idx: 1, cat_ids: [0, 0, 0] }), ts: 1717612500.815073586s
Session: fb_idx: Some(1), peer: [fe80::416:93dd:216a:d50a%2]:65218, peer_nodeid: Some(864992019), local_nodeid: 1121512030, local: 4, remote: 48265, msg_ctr: 226861159, mode: Case(CaseDetails { fab_idx: 1, cat_ids: [0, 0, 0] }), ts: 1717612500.815073586s

[IM/DM] More intelligent reporting on subscriptions

Since the merge of #147 , we now do have subscriptions and we do report on these.

However, the current implementation is a bit suboptimal, in that it always reports everything, regardless whether any of the attributes reported by the subscription are actually changed.

I also believe that the existing ChangeNotifier idea, which is somewhat implemented throughout the code (but unfinished), might not have a future, as I don't see it helping in anyway to solve the problem:

  • When we get a write or invoke command from a remote peer, we are anyway notified via the AsyncHandler callbacks.
  • When we are modifying the data ourselves, we actually know we are doing this, so we don't need an eager notification from the cluster calling back into us, when the cluster dataver is changed

I think something more fruitful would be if the notification is traversing all clusters it reports on, and trying to detect (possibly by comparing against a preserved set of datavers, or a simpler -hash-based derivation of multiple datavers) if there are changes or not.

Logging updates to improve debugging: adding cluster path information

When an interaction arrives at the device, the TLV contents are logged, but it's not easy to get the cluster path or attribute being read. The general commissioning cluster handlers have some code for invoke commands, but it'd make it easier to debug from log captures if the log line included information about the cluster being queried in a ReadRequest or other requests, like in #102

No issue: collaboration invite

Hello matter-rs,

sorry for creating a non-issue. Please simply close it if that is not interesting for you.

I‘m one of the maintainers of matter.js (also project under project-chip orga) and we implement matter in JavaScript/typescript.

To support the open source community in developing with and for matter I also created a discord called „matter-integrators“ where I would like to invite you. There are already other open source projects like the tasmota matter implementations in and beside building a developer community it also started to be a good place to exchange opinions on matter specs and how to read/interpret it ;-).

Thank you and maybe see you there ;-)

Ingo

ESP-IDF build instructions

Hi,

The instructions for how to build rs-matter for esp-idf were removed in pull request #129 citing that support was upstreamed. Unfortunately it is now unclear from looking at the repository whether using matter-rs on an ESP32 is supported, and if so what networking stack is supported (wifi, threads... etc).

Some clarification with minimal build instructions on how to build rs-matter for ESP-IDF would be amazing.

Meeting, 2023-10-06

(@kedars We should probably open the "Discussions" functionality in the GH project, and then make one item there, "Meetings". Or at least this is what the esp-rs folks practice.)

CC: @jasta @MabezDev @jessebraham

Overall: Intro, availability of folks

Did a review of the existing issues / errors:

  • #109

    • Hypothesis 1: (Kedars) extra/changed parameters in the ASN.1 certificate encoding that need processing
    • Hypothesis 2: (Ivan) the Fabric ID coming with the cert does not match the one in the session (?)
    • Action: @ivmarkov to try to repro the bug with his Alexa controller
  • #103

    • Will be addressed by PR #107
  • #102 (also PR #107)

    • Seems Matter C++ SDK returns empty string instead of UnsupportedAttribute (to be confirmed)
    • Kedar reported that for him provisioning does work with a Matter C++ SDK device (but then again, that might be because the C++ SDK returns an empty string)
    • Action: @kedars to check with chiptool the Matter C++ device what exactly it returns for UniqueId - empty strong or not
    • Action: @kedars to check another optional attribute with the Matter C++ device; if both return default values with the Matter C++ SDK then we should do the same; if only UniqueId returns a default values, we should treat it as a special case, as we do now
  • #100

  • #108

    • Agreement is we would not be doing this
    • Action: @kedars, Close
  • #94

  • #101

    • The source of confusion here is that the OnOffCluster sample implementation is part of the rs-matter library, while it should be provided as part of the example, to make it clear that users should provide their own one
    • Action: @ivmarkov - open a PR

Did a review of the longer term roadmap; Top 3 roadmap items seem to be:

  • #41

    • In a way this is also the way to provision for Wifi
    • Also the way to provision for Thread
    • Ivan noted that there is another way for WiFi provisioning (SoftAP with a special name, according to the spec)
    • Action, @kedars - to check if any company has implemented this ^^^ else it might become optional part of the spec and would not be a widely used feature anyway
    • Bjoern mentioned that he is looking into Thread support; seems that also is a sub-item of BLE provisioning
  • #35

    • Ivan suspects the lack of this is the reason why provisioning with Google controller fails with "device not found" at the end, however Kedar believes this is most likely an mDNS issue (so much easier to fix)
    • In any case consensus is we need this functionality
    • Ivan mentioned this would most likely need Exchange in Initiator mode to be supported; Kedar believes it should actually be a long-running Exchange initiated by the controller
    • Action, @kedars, all: check in the spec if subscription events are delivered over a long running Exchange/Transaction opened by the controller, or (as Ivan believes) each subscription report is a new exchange initiated by the device
  • #37

    • Should be relatively easy to implement, now that we are async based
    • (Not mentioned during the discussion) After that we probably need another roadmap item - "Consolidate most of exchange logic in ExchangeMgr"; also related to #35 ^^^
  • #36

    • Not one of the top 3, but maybe still important; Kedar explained this is the vehicle for delivering notifications of a type "new fabric was provisioned", which might be important
    • Action, @kedars - check if this part of the spec is actually implemented by anybody

Code coverage in CI

It would be useful for us to have code coverage in CI, especially for the crypto backends.
Depending on what service we use, this might require some integrating the repo to an external service, e.g. coveralls.

I can work on the Github Actions part and figure out how coverage will work for mutually exclusive targets, then I can leave some instructions for how a repo admin can enable CI on a service.

Result type returned by `Attribute::new`

Here a Result is returned, whereas an error case is not handled. Since no error case is handled, I'd like to suggest returning Self instead of a result, which would remove a lot of question mark operators within the library. This is not a minor refactor, therefore I'd like to post it as an issue first. Would love to hear what you think!

[BUG] Unable to commission with Apple Home

On M1 on the sequential branch running the onoff_light example and commissioning with Apple Home the device is unable to be commissioned.
Using chip-tool it works.

I'm able to commission my own custom devices based on the main repo (project-chip/connectedhomeip) just fine.

The only Error I can see in the log is the following :

[2023-07-12T11:15:48Z ERROR matter::acl] ACL Disallow for subjects [1921388213, ] fab idx 1
[2023-07-12T11:15:48Z ERROR matter::acl] ACLS: []

Any pointers in the right direction would be appreciated.

Here is the full log :
error.log

Provide decent error message for wrapped errors

Add an error: Box<dyn std::error::Error> member to the Error enum here. Then include the original error message (and possibly its backtrace, if any) in the Debug and Display impl for the matter-rs Error enum.

Just like the backtrace member, it should be enabled only when both std and backtrace features are enabled, as it would be bringing non-trivial cost to the unhappy path.

Yet very useful for proper diagnostics of errors originating outside of matter-rs itself.

Thanks!

Hi,

Thanks for picking up the work to create a Rust version of the Matter implementation. Not an easy endeavour.
I've done a bit of experimenting with your "old" repository and am looking forward to see how this work develops.

My main objective is to replace the current HomeKit bridge that was developed with (https://github.com/ewilken/hap-rs) with a Matter equivalent.

I have an Apple eco-system with Somfy smart devices and use the bridge to connect the two worlds.
If needed, I may be able to help test your code with Apple Home.

Kind regards,
Marcel

PS.
I'll do a PR that implements a bunch of Clippy suggestions. That should help quiet the compilation. 😄

Provisioning with Amazon Alexa fails with Invalid Cert error during the Case 3 step

reproduction:

  1. cloned the current main branch and run cargo build on my machine
  2. opened the Alexa App on my phone to add a new device, a matter device was recognised suggested
  3. scanned the QR code from the terminal with the phone

expected: successful pairing
outcome: The Alexa App says: "Something gone wrong, an unexpected error occurred, please try again later" (Translated)

the important lines could be

[2023-10-03T15:07:59Z ERROR rs_matter::secure_channel::case] Certificate Chain doesn't match: Invalid: 
[2023-10-03T15:07:59Z ERROR rs_matter::tlv::parser] Invalid value found: 0 self TLVListIterator { buf: [1, 0, 0, 0, 0, 0, 2, 0], current: 8 } size 1

log.txt

Explain how to install/Link the `chip-tool` in readme

I am new to matter and do not know anything about it.
The readme.md mentions a chip-tool, but there is no link to this tool.
At first, I thought that I installed this tool via espup, but that is not the case.
Through googling, I found this site and I guess that is the mentioned tool?

It would make sense to explain in the readme, how one can install the tool/where one can find it.

Error: environment variable not found

  1. generated a new project with cargo generate esp-rs/esp-idf-template cargo
  2. added rs-matter as a dependency
  3. copied the onoff_light example code into it
  4. used the provided command from the README.md
    export MCU=esp32; export CARGO_TARGET_XTENSA_ESP32_ESPIDF_LINKER=ldproxy; export RUSTFLAGS="-C default-linker-libraries"; export WIFI_SSID=ssid;export WIFI_PASS=pass; cargo build --no-default-features --target xtensa-esp32-espidf -Zbuild-std=std,panic_abort

expected: successful build
outcome: error: failed to run custom build command for rs-matter v0.1.1
Error: environment variable not found

quite not sure which env variable is not set

Consider `no_std` support

To run this on an MCU it would be beneficial to support no_std environments

I did a POC "from scratch" which is no_std and no_alloc here: https://github.com/bjoernQ/bare-matter (the code is very bad but might be an inspiration)

I guess making this completely no_alloc will be hard but at least no_std should be possible

Planned support for zigbee?

I'm almost starting a zigbee project in rust. Will this project eventually have zigbee support? I'd like to not reinvent the wheel

How to actually implement an LED light in onff_light example?

I'm confused where I would add user code to actually do something with the on/off commands are received, am I missing something from the example code? It would seem that this is internally handled by OnOffCluster with no ability for me to observe changes like we see with other clusters like MediaPlaybackCluster. Perhaps we could include some simple print debugging or something when the user code would be expected to interact with a physical device to make this clearer for folks?

[Error handling] Put extra logging and propagate backtraces

For a certain set of errors, specifically ErrorCodes:

  • Crypto
  • TLSStack
  • BtpError
  • MdnsError
  • NoNetworkInterface (we should actually rename this to NetworkError)
  • StdIoError
  • maybe a few more...?

... we should:

  • Always grab the original backtrace (if feature backtrace is enabled)
  • ... and keep the original error as a Box<dyn Error> (if feature std is enabled, and also in future if feature alloc is enabled given that ). Note that we currently preserve the original error only if BOTH std and backtrace are enabled, which is probably a bit too paranoid
  • Log the original error with error! otherwise

... to get extra context for debugging. Because these errors are:

  • Wrappers for lower-level errors in their respective stacks
  • We need extra info what happened for debugging

The cost of preserving the original error should not be that high as we don't expect these errors to happen frequently, but unfortunately we can only due it in the presence of alloc. Without alloc, preserving the original errors means generics which will virally pollute all our APIs which is just plain impossible to handle.

We might even decide to model these errors in a different way from the rest. To be decided.

Event loop for long running cluster commands.

Hi, I'm implementing some of the clusters related to audio devices - level control, audio output, etc.
I will open a PR for them soon but there are some long-running commands that cause issues.

Specifically with level control - A lot of the commands contain optional transition time - they can take up X amount of seconds to complete. This obviously can't block the main thread as everything will time out and we need to issue a response right after we process it.
In order to have it run in the background, I've implemented a background thread for the level control cluster that will update some values and the main thread can update the data model from that whenever a command is issued. This has a problem currently - values are updated from this update-store only on writes, read interactions are not processed through the specific cluster implementations. So if we're slowly updating the level of a device from X to Y in the background, reads will not show this until an actual cluster commands is issued.

My question is, should I make this like a cluster trait for all clusters to implement on top of if needed? I assume some other clusters to be implemented in the future will also require handling of long running commands.

Any suggestions, or other ideas how to do this properly ?

Support dimmable and colored lights

This project looks really cool to me to build some easy and cross compatible lights with something like a raspberry pi or any other wireless connected device. I'd really like to use it with my custom built light, without needing to implement something specific to my current solution (I currently use HomeAssistant MQTT). It would be really nice to have dimmable, CCT, RGB and RGB-CCT lights supported by this SDK, that could make it really cool for home projects. (Also switches would be a great addition, but one thing at a time)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.