Biến ThingsBoard thành "Cửa Sổ" Nhìn Vào Bản Vẽ Kỹ Thuật: Hành Trình Xây Dựng Widget DXF Viewer
Hôm nay, tôi muốn chia sẻ với các bạn một dự án nhỏ nhưng cực kỳ thú vị mà tôi vừa hoàn thành: một Widget xem file DXF trên nền tảng ThingsBoard. Nếu bạn đang làm việc với các hệ thống SCADA, tự động hóa công nghiệp, hoặc đơn giản là muốn trực quan hóa các bản vẽ kỹ thuật CAD (Computer-Aided Design) ngay trên dashboard ThingsBoard của mình, thì bài viết này chính là dành cho bạn!

Chào các bạn, những người đam mê IoT và công nghệ!
Hôm nay, tôi muốn chia sẻ với các bạn một dự án nhỏ nhưng cực kỳ thú vị mà tôi vừa hoàn thành: một Widget xem file DXF trên nền tảng ThingsBoard. Nếu bạn đang làm việc với các hệ thống SCADA, tự động hóa công nghiệp, hoặc đơn giản là muốn trực quan hóa các bản vẽ kỹ thuật CAD (Computer-Aided Design) ngay trên dashboard ThingsBoard của mình, thì bài viết này chính là dành cho bạn!
Tại Sao Lại Là DXF Trên ThingsBoard?
Bạn có bao giờ nghĩ đến việc kết nối dữ liệu cảm biến từ nhà máy của mình với bản vẽ bố trí chi tiết của nhà máy đó không? Hoặc hiển thị trạng thái hoạt động của một dây chuyền sản xuất trực tiếp trên sơ đồ kỹ thuật? Đó chính là ý tưởng ban đầu của tôi. ThingsBoard là một nền tảng IoT mạnh mẽ với khả năng thu thập, xử lý và trực quan hóa dữ liệu tuyệt vời. Tuy nhiên, việc hiển thị các bản vẽ CAD như DXF không phải là tính năng có sẵn.
File DXF (Drawing Exchange Format) là một định dạng file CAD phổ biến được sử dụng rộng rãi để trao đổi dữ liệu giữa các ứng dụng CAD khác nhau (như AutoCAD). Việc có thể xem trực tiếp các file này trên ThingsBoard sẽ mở ra vô vàn khả năng mới cho việc giám sát và quản lý.
Thử thách đặt ra là làm thế nào để "dạy" ThingsBoard hiểu và hiển thị được những bản vẽ phức tạp này. Và đó là lúc tôi bắt tay vào viết một widget tùy chỉnh!
"Mổ Xẻ" Widget: Những Thành Phần Chính
Để biến ý tưởng thành hiện thực, tôi đã cần đến một vài "trợ thủ" đắc lực và những đoạn mã JavaScript không quá phức tạp.
1. Nền Tảng 3D: Three.js
Việc đầu tiên và quan trọng nhất là làm sao để hiển thị các đối tượng 2D/3D từ file DXF. Tôi đã chọn Three.js – một thư viện JavaScript mạnh mẽ để tạo và hiển thị đồ họa 3D trên trình duyệt. Three.js cho phép tôi tạo ra một "khung cảnh" (scene), "camera" để nhìn vào khung cảnh đó, và "bộ dựng hình" (renderer) để biến tất cả thành những gì bạn thấy trên màn hình.
// Cài đặt scene, camera, và renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000); // Nền đen
const camera = new THREE.PerspectiveCamera(75, threeContainer.clientWidth / threeContainer.clientHeight, 0.001, 100000);
camera.position.set(0, 0, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setSize(threeContainer.clientWidth, threeContainer.clientHeight);
threeContainer.appendChild(renderer.domElement);2. "Đọc Hiểu" Ngôn Ngữ DXF: Bộ Phân Tích (Parser) Tùy Chỉnh
File DXF không phải là định dạng dễ đọc trực tiếp. Nó chứa các mã nhóm (group codes) và giá trị tương ứng để mô tả từng đối tượng (đường thẳng, hình tròn, văn bản, v.v.). Tôi đã phải viết một bộ phân tích (parser) tùy chỉnh để đọc từng dòng trong file DXF và chuyển đổi chúng thành các đối tượng JavaScript dễ xử lý hơn.
Đây là phần thú vị nhất, vì nó giống như việc bạn đang "dịch" một ngôn ngữ cổ đại sang ngôn ngữ hiện đại vậy! Tôi đã phải nghiên cứu cấu trúc của file DXF để biết mã nào đại diện cho tọa độ, bán kính, tên layer, màu sắc, v.v.
// Đoạn mã phân tích DXF (trích lược)
function parseDXF(dxfText) {
const lines = dxfText.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
const entities = [];
// ... logic đọc từng dòng, xác định mã nhóm và giá trị
// ... xây dựng các đối tượng entity như LINE, CIRCLE, TEXT
return entities;
}Một điểm cần lưu ý ở đây là tôi đã thêm vào các hàm isValidCoordinate và validateAndCleanEntity. Tại sao ư? Bởi vì các file DXF có thể chứa dữ liệu không hợp lệ hoặc bị hỏng, và chúng ta không muốn những dữ liệu đó làm hỏng widget của mình! Các hàm này giúp loại bỏ các "thực thể ma" (như đường thẳng có độ dài bằng 0, hình tròn có bán kính âm, hoặc tọa độ không hợp lệ) trước khi chúng được đưa vào Three.js. Điều này giúp tăng tính ổn định và hiệu suất của widget.
3. Chuyển Đổi Sang Đối Tượng 3D: Geometry Creation
Sau khi đã "hiểu" được file DXF, bước tiếp theo là biến các đối tượng DXF thành các đối tượng 3D mà Three.js có thể hiển thị. Ví dụ, một LINE trong DXF sẽ trở thành một THREE.Line trong Three.js, với các điểm đầu và cuối được lấy từ dữ liệu DXF.
// Đoạn mã tạo hình học từ entity DXF (trích lược)
function createGeometryFromDXF(entities) {
const group = new THREE.Group(); // Nhóm tất cả các đối tượng 3D
entities.forEach(entity => {
const color = getColorFromACI(entity.color); // Chuyển đổi màu AutoCAD sang mã hex
const material = new THREE.LineBasicMaterial({ color: color });
let object = null;
switch (entity.type) {
case 'LINE':
object = new THREE.Line(new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(entity.data.x, entity.data.y || 0, entity.data.z || 0),
new THREE.Vector3(entity.data.x2, entity.data.y2 || 0, entity.data.z2 || 0)
]), material);
break;
case 'CIRCLE':
// ... tạo hình học cho hình tròn
break;
// ... và các loại entity khác
}
if (object) {
group.add(object);
// Lưu trữ đối tượng vào layer tương ứng
layers.get(entity.layer).objects.push(object);
}
});
return { group: group, validEntityCount: validEntitiesCount, filteredEntityCount: filteredEntitiesCount };
}
Một cải tiến quan trọng ở đây là việc tôi đã xử lý một lỗi "bí ẩn" gây ra những đường trắng nhỏ không mong muốn xuất hiện từ gốc tọa độ (0,0,0). Sau nhiều lần thử và sai, tôi phát hiện ra rằng một số phần mềm CAD đôi khi tạo ra các đoạn Polyline cực kỳ nhỏ, gần như vô hình, bắt đầu hoặc kết thúc tại gốc tọa độ, đặc biệt là trên các layer nhất định. Bằng cách thêm logic kiểm tra và lọc bỏ các đoạn này (như bạn thấy trong phần LWPOLYLINE và POLYLINE của createGeometryFromDXF), vấn đề đã được giải quyết triệt để!
4. Tương Tác Người Dùng: Di Chuyển và Điều Khiển
Một widget tốt không chỉ hiển thị mà còn cho phép người dùng tương tác. Tôi đã triển khai các tính năng cơ bản như:
Xoay bản vẽ: Kéo chuột trái.
Phóng to/Thu nhỏ: Lăn chuột giữa (cuộn chuột).
Dịch chuyển (Pan): Kéo chuột phải.
Tải file DXF: Cho phép người dùng tải lên bản vẽ của riêng họ.
Tải file mẫu: Để nhanh chóng kiểm tra widget.
Fit to View / Reset View: Điều chỉnh camera để hiển thị toàn bộ bản vẽ hoặc trở về trạng thái ban đầu.
Điều khiển Layer: Ẩn/hiện các lớp (layer) khác nhau trong bản vẽ, giúp người dùng tập trung vào thông tin cần thiết.
Tất cả những điều này đều được xử lý bằng các sự kiện chuột (mouse events) và cập nhật vị trí camera trong Three.js.
Tích Hợp Vào ThingsBoard
Cuối cùng, tất cả các đoạn mã trên được gói gọn trong cấu trúc của một widget ThingsBoard. Hàm self.onInit là điểm khởi đầu, nơi widget được khởi tạo và các thành phần HTML, Three.js được thiết lập.
self.onInit = function() {
const container = document.createElement('div');
// ... thiết lập style cho container
self.ctx.$container.append(container);
createDXFViewer(container); // Gọi hàm tạo viewer chính
};Kết Quả Đạt Được
Với widget này, giờ đây bạn có thể:
Tải và xem các bản vẽ DXF trực tiếp trên ThingsBoard dashboard.
Tương tác với bản vẽ: xoay, phóng to, thu nhỏ, dịch chuyển.
Kiểm soát hiển thị các layer để tập trung vào thông tin mong muốn.
Hiển thị thông tin tổng quan về bản vẽ như số lượng thực thể, số lượng layer, và giới hạn bản vẽ.
Imagine: Bạn có thể hiển thị dữ liệu nhiệt độ từ cảm biến đặt tại các vị trí cụ thể trên bản vẽ nhà máy, hoặc trực quan hóa luồng công việc bằng cách tô màu các khu vực trên sơ đồ dựa trên trạng thái hoạt động! Khả năng là vô tận.
Tương Lai và Những Cải Tiến Tiếp Theo
Đây chỉ là bước khởi đầu. Trong tương lai, tôi mong muốn phát triển thêm các tính năng như:
Tích hợp dữ liệu từ ThingsBoard: Hiển thị dữ liệu trực tiếp trên bản vẽ DXF (ví dụ: nhấp vào một thiết bị trên bản vẽ để xem dữ liệu cảm biến của nó).
Hỗ trợ thêm các loại entity DXF: Hiện tại, widget tập trung vào các entity cơ bản.
Hiệu suất cao hơn: Tối ưu hóa việc xử lý các file DXF rất lớn.
Tôi hy vọng bài viết này đã mang lại cho các bạn cái nhìn thú vị về cách xây dựng một widget ThingsBoard từ con số 0 để giải quyết một nhu cầu cụ thể. Đôi khi, những giải pháp sáng tạo nhất lại đến từ việc kết hợp các công nghệ sẵn có theo một cách mới mẻ.
Hãy thử nghiệm và cho tôi biết suy nghĩ của bạn nhé! Cảm ơn vì đã đọc!