Hướng dẫn chi tiết triển khai OpenThread Commissioner bằng Java


Summary

Bài viết này khám phá chi tiết cách triển khai OpenThread Commissioner bằng Java, mang đến những giá trị thiết thực cho những ai đang làm việc trong lĩnh vực IoT. Tôi thật sự ấn tượng với khả năng mà JmDNS mang lại trong việc phát hiện Router Biên một cách dễ dàng và hiệu quả. Key Points:

  • Bài viết hướng dẫn sử dụng JmDNS để phát hiện Router Biên OpenThread, cho phép tối ưu hóa việc quản lý mạng một cách hiệu quả hơn so với các phương pháp truyền thống.
  • Nội dung bài viết nhấn mạnh tầm quan trọng của việc quản lý trạng thái kết nối và xử lý lỗi tự động, giúp đảm bảo sự ổn định cho hệ thống IoT.
  • Cuối cùng, bài viết cung cấp cái nhìn sâu sắc về ứng dụng thực tiễn của OTBR trong các lĩnh vực như tự động hóa nhà ở và quản lý đô thị thông minh.
Nhìn chung, bài viết không chỉ dừng lại ở khía cạnh kỹ thuật mà còn mở ra nhiều hướng đi mới cho người đọc trong việc áp dụng công nghệ vào đời sống.

Giới thiệu về triển khai OpenThread Commissioner trong Java

### Triển khai OpenThread Commissioner trong Java

Hướng dẫn từng bước để xây dựng một ứng dụng Java thuần túy cho việc ủy quyền bên ngoài OpenThread. Trong một bài viết trước, chúng ta đã khám phá cách xây dựng và sử dụng ứng dụng Android như một ủy viên bên ngoài để đưa các thiết bị Thread vào mạng. Bài viết này sẽ tiến thêm một bước nữa bằng cách trình bày cách thực hiện một ủy viên bên ngoài dựa trên Java.

Quá trình ủy quyền cho Thread bao gồm những bước chính sau đây:
1. **Khám phá Router Biên**
2. **Kết nối với Router Biên**
3. **Thêm quy tắc tham gia**
4. **Tham gia vào Mạng Thread**

Trong hướng dẫn này, chúng tôi sẽ triển khai các bước này trong một ứng dụng Java, cung cấp phương pháp rõ ràng và có cấu trúc cho việc ủy quyền bên ngoài trong OpenThread.

Để hiểu rõ hơn về cách thức hoạt động, chúng ta cần xem xét giao tiếp giữa Commissioner và các thiết bị trong mạng lưới, bao gồm phát hiện thiết bị, xác thực và cấu hình nó sao cho phù hợp nhất với yêu cầu của hệ thống.

Ngoài ra, cũng nên nhắc đến những thư viện hữu ích hỗ trợ cho việc triển khai như Java Threading hoặc RESTful APIs để tương tác hiệu quả hơn với dịch vụ mà bạn đang sử dụng.

Cuối cùng, hãy chú ý đến các tham số cấu hình có thể điều chỉnh nhằm tối ưu hóa hiệu suất của ứng dụng như thời gian phản hồi hay mức độ bảo mật cần thiết cho từng loại kết nối và dữ liệu mà bạn đang xử lý.

Khám phá Router Biên như thế nào

Để khám phá Router Biên, chúng ta có thể sử dụng JmDNS để thực hiện việc phân giải DNS cho router này. Dịch vụ của router biên được đăng ký với tên "__meshcop._udp.local._" và chúng ta có thể xác định nó trong mạng nơi mà mDNS đã được kích hoạt.

### Người nghe dịch vụ DNS
Người nghe dịch vụ sẽ lắng nghe các sự kiện khi có dịch vụ mới được thêm vào, bị xóa hoặc được phân giải.

public class OTBRDiscoverer implements ServiceListener {
public void serviceAdded(ServiceEvent serviceEvent) {
logger.debug("Dịch vụ đã được thêm: {}", serviceEvent.getInfo());
}

@Override
public void serviceRemoved(ServiceEvent serviceEvent) {
logger.debug("Dịch vụ đã bị xóa: {}", serviceEvent.getInfo());
}

@Override
public void serviceResolved(ServiceEvent serviceEvent) {
logger.debug("Dịch vụ đã được phân giải: {}", serviceEvent.getInfo());
try {
String networkName = serviceEvent.getInfo().getPropertyString(KEY_NETWORK_NAME);
int otbrPort = serviceEvent.getInfo().getPort();


Trong phần này, chúng ta cũng nên nói về nguyên lý hoạt động của router biên. Nó đóng vai trò quan trọng trong việc kết nối và giao tiếp với các thiết bị trong mạng OpenThread, giúp duy trì một kết nối ổn định và hiệu quả hơn.

Về mặt phần cứng, thường thì các loại chip như ESP32 hoặc Nordic nRF52840 sẽ được sử dụng cho router biên này. Bên cạnh đó, người dùng cũng có khả năng tùy chỉnh nhiều tham số khác nhau như độ trễ truyền tải hay băng thông tối ưu để cải thiện hiệu suất mạng tùy theo nhu cầu cụ thể.

Cuối cùng, ứng dụng thực tế của router biên rất đa dạng; ví dụ như trong các tình huống tự động hóa nhà ở hay quản lý đô thị thông minh, nó mang lại những lợi ích không nhỏ cho người dùng cũng như nâng cao chất lượng cuộc sống hàng ngày.
Extended Perspectives Comparison:
BướcMô tảCông nghệ/Thư việnThông tin cần thiếtKết quả mong đợi
1. Khám phá Router BiênSử dụng JmDNS để phát hiện các dịch vụ router biên trong mạng.JmDNSĐịa chỉ IP, cổng của router biên.Dịch vụ đã được giải quyết.
2. Kết nối với Router BiênTính toán PSKc và kết nối Ủy viên với Bộ định tuyến biên.Java Networking APIPSKc từ CLI hoặc tự tạo.Kết nối thành công với Router.
3. Thêm quy tắc tham giaCho phép tất cả các thiết bị tham gia bằng cách sử dụng PSKd.Java CompletableFutureID Joiner, Steering Data.Tất cả Joiners đều được chấp nhận.
4. Tham gia vào Mạng ThreadThiết bị cố gắng tham gia mạng sử dụng PSKD đã cung cấp.Firmware hỗ trợ ThreadPre-Shared Key for Device (PSKD).[Xác nhận sự tham gia thành công của thiết bị].

Kết nối với Router Biên ra sao

Trong hàm _serviceResolved_, chúng ta có thể lấy được thông tin chi tiết về router biên, bao gồm địa chỉ IP, cổng và các thông tin mạng khác cần thiết cho việc kết nối sau này. Ví dụ, mã lệnh dưới đây sẽ giúp bạn trích xuất các thông tin này từ sự kiện dịch vụ. Đầu tiên, ta lấy được ID PAN mở rộng (extPanId) của dịch vụ, rồi kiểm tra xem có địa chỉ IPv4 nào không. Nếu có ít nhất một địa chỉ IPv4, chúng ta sẽ sử dụng địa chỉ đầu tiên để tạo đối tượng OTBRInfo với tên mạng và cổng tương ứng.

Khi thực hiện quá trình này, điều quan trọng là đảm bảo rằng bạn đóng đúng phiên làm việc với JNDI sau khi hoàn tất để tránh rò rỉ tài nguyên. Việc ghi lại thông tin như đã giải quyết dịch vụ thành công cũng rất hữu ích cho việc theo dõi và gỡ lỗi. Hãy nhớ rằng trong môi trường thực tế, bạn cũng cần cân nhắc đến nguyên lý hoạt động của OpenThread và cách mà Commissioner tương tác với Router Biên để thiết lập kết nối ổn định hơn.

Để triển khai hiệu quả hơn nữa, hãy chú ý đến loại chip hỗ trợ OpenThread mà bạn đang sử dụng cùng với các giao thức mạng thích hợp. Ngoài ra, hướng dẫn cấu hình cụ thể cũng như giải thích về các tham số tùy chỉnh sẽ giúp người đọc dễ dàng trong quá trình thực hiện hơn.

Thêm quy tắc Joiner dễ dàng

### Thêm Listener Dịch Vụ DNS
Thêm listener cho loại dịch vụ '__meshcop._udp.local._'.

try {
jmdns = JmDNS.create(getLocalHostIP());
jmdns.addServiceListener(MDNS_SERVICE_TYPE, new OTBRDiscoverer());
logger.info("Đang khám phá Border Router tại {}", MDNS_SERVICE_TYPE);
} catch (IOException e) {
logger.warn("Không thể tạo JmDNS {}", e.getMessage());
}


Lưu ý: Hãy lấy địa chỉ IP cục bộ thay vì localhost, đôi khi "localhost"/127.0.0.1 không hoạt động.

## 2. Kết nối với Border Router
Khi một border router đã được phát hiện, chúng ta có thể kết nối với nó bằng PSKc.

### Khóa Chia Sẻ Trước cho Ủy Quyền (PSKc)
Chúng ta có thể lấy PSKc từ CLI của Border Router như sau:

$ sudo ot-ctl pskc 445f2b5ca6f2a93a55ce570a70efeecbdone$


Nếu bạn không có quyền truy cập vào CLI của Border Router, chúng ta cũng có thể tạo khóa này thông qua lập trình.

Việc nắm rõ cách thức hoạt động và những bước cần thực hiện sẽ giúp người dùng dễ dàng hơn trong việc kết nối và quản lý mạng lưới OpenThread một cách hiệu quả hơn. Hãy đảm bảo rằng các tham số cấu hình như thời gian chờ hay độ ưu tiên thiết bị đã được điều chỉnh phù hợp để tối ưu hóa quá trình kết nối nhé!


Thêm quy tắc Joiner dễ dàng Free Images


Cách gia nhập mạng Thread từ thiết bị

Để kết nối giữa Ủy viên với Bộ định tuyến biên (Border Router), trước tiên bạn cần tính toán PSKC (Pre-Shared Key Cache) bằng cách sử dụng các thông tin như mật khẩu, tên mạng và ID PAN mở rộng. Cụ thể, đoạn mã dưới đây giúp thực hiện việc này:

pskc = commissioner.computePskc(passphrase, otbrInfo.getNetworkName(), new ByteArray(Utils.getByteArray(otbrInfo.getExtendedPanId())));


Trong đó, _mật khẩu_, _tên mạng_ và _ID PAN mở rộng_ được xác định trong Bộ định tuyến biên của OpenThread. Sau khi đã có PSKC, bạn có thể tiến hành kết nối Ủy viên với Bộ định tuyến biên tại địa chỉ và cổng đã phát hiện:

commissioner.connect(pskc, otbrInfo.getOtbrAddress(), otbrInfo.getOtbrPort())
.thenRun(() -> {
logger.info("Kết nối Ủy viên thành công!");
})
.exceptionally(ex -> {
logger.error("Kết nối Ủy viên thất bại: {}", String.valueOf(ex));
return null;
});


Quá trình này sẽ khởi động việc yêu cầu từ phía Ủy viên trong mạng Thread. Lưu ý rằng chỉ một ủy viên duy nhất có thể hoạt động tại một thời điểm trong mạng này.

Sử dụng PSKc để kết nối hiệu quả

Khi ủy viên đã kết nối với Bộ định tuyến biên, chúng ta có thể bắt đầu thêm các quy tắc cho thiết bị tham gia. Trong bước này, chúng ta sẽ cho phép tất cả các thiết bị tham gia bằng cách sử dụng Khóa Chia Sẻ Trước (PSKd), hay còn gọi là khóa tham gia. Việc triển khai PSKd giúp tối ưu hóa quá trình xác thực và tạo điều kiện thuận lợi cho việc kết nối các thiết bị mới vào mạng lưới. Điều này cũng đồng nghĩa rằng, với một khóa mạnh mẽ và được quản lý đúng cách, chúng ta có thể bảo đảm an toàn hơn cho hệ thống mạng của mình.

Quản lý và theo dõi Joiners qua ứng dụng Java

Đoạn mã này sẽ thêm một Joiner với dữ liệu điều khiển là '_0xFF' và '_0x00' làm ID của Joiner. Sau khi thực hiện phương thức `enableAllJoiners(pskd)`, nếu thành công, nó sẽ ghi lại thông tin rằng tất cả các Joiners đã được chấp nhận tại PSKD: {pskd}. Nếu có lỗi xảy ra trong quá trình thêm Joiner, điều đó sẽ được ghi lại với thông báo lỗi kèm theo chi tiết về vấn đề gặp phải.

Thực hiện lệnh để kiểm tra trạng thái Commissioner

ID của Joiner thường là một hàm băm sha256 từ EUI64 của thiết bị đang cố gắng tham gia. Để thêm joiner, chúng ta sử dụng đoạn mã sau: Commissioner.addJoiner(steeringData, joinerId); Tiếp theo, chúng ta tạo một bộ dữ liệu cho Ủy viên như sau: CommissionerDataset commDataset = new CommissionerDataset(); commDataset.setPresentFlags(commDataset.getPresentFlags() & ~CommissionerDataset.kSessionIdBit); commDataset.setPresentFlags(commDataset.getPresentFlags() & ~CommissionerDataset.kBorderAgentLocatorBit); commDataset.setPresentFlags(commDataset.getPresentFlags() | CommissionerDataset.kSteeringDataBit); commDataset.setSteeringData(steeringData); nativeCommissioner.setCommissionerDataset(commDataset);

Đồng thời, trong lớp xử lý Ủy viên (CommissionerHandler), chúng tôi cũng duy trì một bản đồ cục bộ để lưu trữ ID của joiner và PSKd. Mỗi khi có một joiner mới được đăng ký, chúng tôi sẽ thêm thông tin này vào bản đồ với PSKd tương ứng. Việc quản lý những thông tin này rất quan trọng nhằm đảm bảo quy trình kết nối diễn ra suôn sẻ và an toàn hơn cho các thiết bị tham gia mạng lưới.

Hướng dẫn chạy ứng dụng OpenThread Commissioner trong Java

Lớp `ThreadCommissioner` kế thừa từ `CommissionerHandler`, trong đó có một bản đồ (Map) tên là `joiners` để lưu trữ thông tin về những thiết bị tham gia. Phương thức `enableAllJoiners` sẽ được gọi khi cần kích hoạt tất cả các thiết bị tham gia, với tham số đầu vào là mã PSKD (`pskd`). Phương thức này trả về một đối tượng CompletableFuture
, cho phép thực hiện các tác vụ không đồng bộ.

Khi phương thức này được gọi, nó sẽ chạy một tác vụ bất đồng bộ. Trong quá trình này, nếu có lỗi xảy ra thì phương thức `throwIfFail` sẽ ném ra ngoại lệ. Nếu mọi thứ diễn ra suôn sẻ, mã hex của ID joiner và mã PSKD sẽ được thêm vào bản đồ joiners.

Đặc biệt, khi một thiết bị kết thúc Thread bắt đầu quy trình tham gia mạng lưới, class `CommissionerHandler` trong ứng dụng Java sẽ nhận được callback từ sự kiện `_onJoinerRequest`. Tại đây, chúng ta sẽ trả lại mã PSKD cho thiết bị đang cố gắng tham gia mạng lưới Thread. Điều này giúp thiết bị có thể kết nối thành công với mạng lưới IoT sử dụng giao thức Thread.

Giao thức Thread tương tác rất linh hoạt với các thiết bị IoT và việc cấu hình như địa chỉ IP hay cổng (port) cũng quan trọng trong quá trình kết nối giữa Commissioner và Router. Để hiểu rõ hơn về cách triển khai thực tế ứng dụng này, bạn có thể xem xét ví dụ cụ thể về đoạn mã nguồn liên quan đến quá trình khởi tạo kết nối và quản lý joiners.

Cách đóng góp cho dự án mã nguồn mở OpenThread

public String onJoinerRequest(ByteArray joinerId) {        
String joinerIdStr = Utils.getHexString(joinerId);
logger.info("Một joiner (ID={}) đang yêu cầu commissioning", joinerIdStr);
String pskd = joiners.get(joinerIdStr);
if (pskd == null) {
// Kiểm tra nếu JOINER ID All đã được đăng ký
pskd = joiners.get(Utils.getHexString(computeJoinerIdAll()));
}
return pskd;
}

public void onJoinerConnected(ByteArray joinerId, Error error) {
logger.info("Một joiner (ID={}) đã kết nối với {}", Utils.getHexString(joinerId), error);
}

public boolean onJoinerFinalize(ByteArray joinerId,String vendorName,String vendorModel,String vendorSwVersion,ByteArray vendorStackVersion,String provisioningUrl,ByteArray vendorData) {
logger.info("Một joiner (ID={}) đang hoàn tất", Utils.getHexString(joinerId));
// Cho phép tất cả các joiners.
return true;
}


## Dự án OpenThread Commissioner bằng Java
Chúng tôi đã mã nguồn mở toàn bộ ứng dụng Java [tại đây], hãy theo dõi hướng dẫn trong README để xây dựng ứng dụng Java này.
- Bạn có thể sử dụng thư viện đã biên dịch sẵn từ dự án hoặc tự biên dịch chúng cho nền tảng của bạn.

Sau đó, biên dịch và đóng gói Java Commissioner bằng Maven:
mvn clean package


### Chạy Ứng Dụng OpenThread Commissioner Java
Đi đến thư mục `target/` và thực thi Commission.
cd target  
java -jar openthread-commissioner-java-1.0-SNAPSHOT-jar-with-dependencies.jar

Kết quả mong đợi:
INFO  c.thread.commissioner.OTBRDiscoverer - Đang phát hiện Border Router tại _meshcop._udp.local.
INFO com.thread.commissioner.Runner - Đang phát hiện Border Router...1
INFO com.thread.commissioner.Runner - Đang phát hiện Border Router...2
INFO com.thread.commissioner.Runner - Đang phát hiện Border Router...3
INFO c.thread.commissioner.OTBRDiscoverer - Dịch vụ đã được giải quyết: 172.20.10.20:49154 OpenThreadDemo 1111111122222222

>>> Nhập PSKc (để trống nếu muốn tính toán): 445f2b5ca6f2a93a55ce570a70efeecb

Lệnh:
1. Kiểm tra Trạng thái
2. Bật Tất cả Joiners
3. Thoát

Nhập số lệnh: 1

INFO com.thread.commissioner.Runner - Commissioner kết nối thành công!
INFO com.thread.commissioner.Runner - Trạng thái: kActive

Nếu PSKc không được cung cấp, ứng dụng sẽ yêu cầu tên mạng, Extended PAN ID và mật khẩu để tạo ra nó.

### Bật Joiners tham gia vào Mạng Lưới
Thêm Quy tắc Joiners bằng cách chọn lệnh số 2, điều này sẽ cho phép tất cả các Joiners cho một Pre-Shared Key for Device (PSKD):
Lệnh:
1. Kiểm tra Trạng thái
2. Bật Tất cả Joiners
3. Thoát

Nhập số lệnh: 2

Nhập PSKd cho Tất cả Joiners: JO1NME

INFO c.t.commissioner.ThreadCommission er - enableAllJoiners - steeringData=ffffffffffffffffffffffffffffffff Một Join-er (ID=af5570f5a1810b7a)
2025-03-09 22:00:30 INFO com.thread.commission er.Runner - Tất cả các Join-er đều được chấp nhận với PSKD: JO1NME


### Tham gia từ thiết bị
Để kiểm tra việc tham gia của thiết bị, [xây dựng và flash firmware end-device Thread] với hỗ trợ commissioning.
Thiết bị nên khám phá mạng và cố gắng tham gia sử dụng Pre-Shared Key for Device (PSKD). Khởi động quá trình tham gia với lệnh sau:
> join-er start J01NME thành công của joint-er Done>

Trong trường hợp tham gia thành công, Bộ xử lý Commission ở ứng dụng java sẽ in ra :
INFO c.t.commission er.ThreadCommission er - Một joint-er(ID=ca666d7873988c66) đang yêu cầu commissioning  
INFO c.t.commissio ner.ThreadCom missio ner - Một joint-er(ID=ca666d7873988c66) đã kết nối với OK
INFO c.t.comm ission.er.ThreadC ommissio ner - Một joint-er(ID=ca666d7873988c66) đang hoàn tất


## Cách đóng góp
Chúng tôi luôn hoan nghênh sự đóng góp từ cộng đồng nhằm cải thiện và mở rộng [dự án mã nguồn mở]. Mục tiêu của chúng tôi là tinh chỉnh nó lên một mức độ mà có thể gửi như một PR tới kho lưu trữ chính thức của [OpenThread]. Hãy tham khảo hướng dẫn đóng góp của OpenThread để bắt đầu.

## Tài liệu tham khảo
- [Kết nối thiết bị Thread tới Internet]
- [Hiểu về Commissioner và Join-er]
- [Hiểu về Commissioning bên ngoài – Công cụ CLI]
- [Hiểu về Commissioning bên ngoài – App Android]

Reference Articles

Công cụ và tập lệnh

OTBR cung cấp tập lệnh kiểm thử MeshCoP (Giao thức uỷ quyền lưới) sử dụng OT Commissioner để kiểm thử Uỷ ban bên ngoài. Để biết thông tin về cách sử dụng, hãy ...

Source: OpenThread

Phí hoa hồng trên lưới

Hướng dẫn này trình bày cách triển khai cơ bản trên mạng lưới mà không cần có Trình uỷ quyền hoặc Bộ định tuyến biên bên ngoài. Để tìm hiểu cách sử dụng ...

Source: OpenThread

Phát triển bằng API OpenThread

Trong lớp học lập trình này, bạn sẽ sử dụng OpenThread API để khởi động một mạng Thread, giám sát và phản ứng với các thay đổi về vai trò trên ...

Source: OpenThread

Mô phỏng mạng Thread bằng OpenThread

Chuyển đến thư mục openthread và tạo quy trình CLI cho một thiết bị Thread được mô phỏng bằng cách sử dụng tệp nhị phân ot-cli-ftd .

Source: OpenThread

Xây dựng mạng Thread bằng các bảng nRF52840 và ...

Trong Lớp học lập trình này, bạn sẽ lập trình OpenThread trên phần cứng thực, tạo và quản lý mạng Thread và chuyển thông báo giữa các nút.

Source: OpenThread

Xây dựng mạng luồng với Ban phát triển B91 và OpenThread

Xây dựng mạng luồng với Ban phát triển B91 và OpenThread · 1. Giới thiệu · 2. Điều kiện tiên quyết · 3. Thiết lập chương trình cơ sở · 4. Định cấu hình Bảng điều ...

Source: OpenThread

Mô phỏng mạng Thread bằng OpenThread trong Docker

OpenThread do Google phát hành là một phương thức triển khai nguồn mở của giao thức mạng Thread. Google Nest đã ra mắt OpenThread để cung cấp rộng rãi công nghệ ...

Source: OpenThread

Xây dựng mạng Thread bằng các bo mạch Silicon Labs ...

Trong Lớp học lập trình này, bạn sẽ lập trình OpenThread trên phần cứng thực, tạo và quản lý mạng Thread và chuyển thông báo giữa các nút.

Source: OpenThread

Jochen Feldmann

Expert

Related Discussions

❖ Related Articles