Computer >> Máy Tính >  >> Hệ thống >> MAC

Cách sử dụng hạt Argon để theo dõi vị trí

Bạn đã bao giờ muốn thêm sự hiện diện hoặc theo dõi vị trí vào một dự án? Bạn thất vọng vì các giải pháp (hoặc thiếu các giải pháp đó)?

Đừng lo lắng, bạn không phải là người duy nhất!

Trong bài đăng này, bạn sẽ học cách triển khai một ứng dụng theo dõi và thông báo rất cơ bản. Chúng tôi sẽ sử dụng Particle Argon và Tile Mate.

Cuối cùng, bạn sẽ có thể biết khi nào Ngói có mặt hay không. Ngoài ra, chúng tôi sẽ sử dụng Pushover để gửi thông báo đẩy đến các thiết bị bạn chọn.

Hãy bắt đầu!

Lưu ý trước khi chúng tôi bắt đầu, bài đăng này dài dòng . Bạn có thể tải xuống phiên bản PDF để có thể lưu và xem sau.

Điều tra ban đầu

Thoạt nhìn, ý tưởng sử dụng Ngói không rõ ràng. Lý tưởng nhất là sử dụng điện thoại có vẻ có ý nghĩa hơn. Thật không may, đây không phải là một lựa chọn khả thi. Nó sẽ yêu cầu một số nghiên cứu thêm và tạo ra một ứng dụng Bluetooth iOS.

Vì vậy, ý tưởng sử dụng điện thoại đã ra đời.

Sau đó, tôi nghĩ, "Thiết bị nào làm gì quảng cáo mọi lúc? "

Đó là điều đã dẫn tôi đến con đường của một trình theo dõi như Tile.

Sau khi nó đến, có một số thử nghiệm thông thường. Điểm dừng đầu tiên, ứng dụng Tile.

Cách sử dụng hạt Argon để theo dõi vị trí

Tôi đã có thể kết nối và sử dụng thiết bị. Tôi thậm chí còn làm cho nó phát một giai điệu hấp dẫn. ?

Sau đó, tôi chuyển sang sử dụng một trong các ứng dụng máy quét Bluetooth. Tôi cuộn qua tất cả các kết quả và Bingo. Đã có Ngói!

Cách sử dụng hạt Argon để theo dõi vị trí

Tôi thậm chí đã đợi một vài giờ và kiểm tra lại. Tôi muốn chắc chắn rằng nó sẽ không đi ngủ sau một thời gian. Hóa ra, đó luôn là quảng cáo. Theo như tôi có thể nói, khoảng 8 giây một lần.

Tất cả thử nghiệm này đều dẫn đến một kết luận:nó có thể dễ dàng được sử dụng để phát hiện sự hiện diện.

Bước tiếp theo trong quy trình là cố gắng tìm ra cách làm cho nó hoạt động với Argon.

Quảng cáo

Như chúng ta đã thu thập ở bước trước, chúng ta biết rằng Tile đang quảng cáo khoảng 8 giây một lần. Điều đó có nghĩa là nó sẽ được quét dễ dàng để sử dụng bất kỳ thiết bị nào bao gồm Argon, Zenon hoặc Boron.

Đối với ví dụ này, tôi khuyên bạn nên sử dụng Argon. Điều này là do Bluetooth và Mesh chia sẻ cùng một radio. Khi quét tìm Tile, Xenon kết nối với Mesh thường bỏ sót các gói quảng cáo. Điều này sẽ dẫn đến phủ định sai (và gây thất vọng!).

Cùng dòng, bạn sẽ muốn đảm bảo Argon của bạn được kết nối với không có mạng lưới. Bạn có thể xóa nó bằng CLI. Kết nối thiết bị của bạn với máy tính và chạy lệnh sau:

particle mesh remove <device name/ID>

Đảm bảo rằng bạn thay thế với tên hoặc ID thiết bị của bạn.

Được rồi, quay lại nội dung tốt.

Quảng cáo có thể có một số mục đích khác nhau trong Bluetooth. Mặc dù vậy, thông thường, nó đánh dấu sự bắt đầu của giai đoạn ghép nối. Bằng cách đó, các thiết bị khác biết rằng thiết bị quảng cáo có sẵn.

Ngoài ra, thiết bị quảng cáo sẽ cho biết nó có những dịch vụ gì. Chúng tôi có thể sử dụng kiến ​​thức này để lọc ra các thiết bị không phù hợp.

Ví dụ:đây là ảnh chụp màn hình của các dịch vụ có sẵn trên thiết bị Tile:

Cách sử dụng hạt Argon để theo dõi vị trí

Khi quét, chúng tôi sẽ kiểm tra kỹ thiết bị mà chúng tôi đang kết nối có UUID dịch vụ của 0xfeed hay không .

Tuy nhiên, trước khi đi sâu vào vùng đất Bluetooth, hãy thiết lập ứng dụng của chúng tôi để gỡ lỗi bằng Logger.

Ghi nhật ký

Trong hướng dẫn này, chúng tôi sẽ sử dụng Logger. Nó cho phép bạn hiển thị thông báo nhật ký từ ứng dụng của mình bằng particle serial monitor .

Một trong những tính năng thú vị về trình ghi nhật ký là ý tưởng về hệ thống phân cấp thông báo. Điều này cho phép bạn, nhà thiết kế, tắt tiếng có chọn lọc các thư có thể không cần thiết.

Ví dụ:nếu bạn có tin nhắn được sử dụng để gỡ lỗi. Bạn có thể xóa chúng hoặc bình luận chúng ra. Hoặc, bạn có thể tăng LOG_LEVEL vì vậy chúng bị bỏ qua một cách hiệu quả.

Dưới đây là các cấp độ ghi nhật ký có sẵn trong logging.h trong kho lưu trữ thiết bị-hệ điều hành của Particle:

// Log level. Ensure log_level_name() is updated for newly added levels
typedef enum LogLevel {
    LOG_LEVEL_ALL = 1, // Log all messages
    LOG_LEVEL_TRACE = 1,
    LOG_LEVEL_INFO = 30,
    LOG_LEVEL_WARN = 40,
    LOG_LEVEL_ERROR = 50,
    LOG_LEVEL_PANIC = 60,
    LOG_LEVEL_NONE = 70, // Do not log any messages
    // Compatibility levels
    DEFAULT_LEVEL = 0,
    ALL_LEVEL = LOG_LEVEL_ALL,
    TRACE_LEVEL = LOG_LEVEL_TRACE,
    LOG_LEVEL = LOG_LEVEL_TRACE, // Deprecated
    DEBUG_LEVEL = LOG_LEVEL_TRACE, // Deprecated
    INFO_LEVEL = LOG_LEVEL_INFO,
    WARN_LEVEL = LOG_LEVEL_WARN,
    ERROR_LEVEL = LOG_LEVEL_ERROR,
    PANIC_LEVEL = LOG_LEVEL_PANIC,
    NO_LOG_LEVEL = LOG_LEVEL_NONE
} LogLevel;

Tuyệt vời, cấp độ nhật ký. Nhưng chúng ta sử dụng chúng như thế nào?

Chúng ta có thể sử dụng chúng bằng cách gọi một trong các hàm sau:

Log.trace , Log.info , Log.warn , Log.error .

Ví dụ:

Log.trace("This is a TRACE message.");

Nếu chúng tôi đặt mức nhật ký thành LOG_LEVEL_INFO chúng tôi sẽ chỉ thấy tin nhắn từ Log.info , Log.warnLog.error . LOG_LEVEL_WARN ? Chỉ Log.warnLog.error sẽ hiển thị. (Hy vọng rằng bạn hiểu được ý tưởng.)

Để thiết lập, chúng tôi sẽ đặt mức mặc định thành LOG_LEVEL_ERROR . Chúng tôi cũng sẽ đặt LOG_LEVEL dành riêng cho ứng dụng thành LOG_LEVEL_TRACE . Kết quả cuối cùng sẽ giống như thế này

// For logging
SerialLogHandler logHandler(115200, LOG_LEVEL_ERROR, {
    { "app", LOG_LEVEL_TRACE }, // enable all app messages
});

Bằng cách này, chúng tôi không bị spam các thông báo nhật ký DeviceOS. Ngoài ra, chúng tôi nhận được tất cả các thông báo thích hợp từ chính ứng dụng.

Nhân tiện, nếu bạn muốn đặt thiết bị của mình thành một LOG_LEVEL bạn có thể thiết lập nó như thế này:

SerialLogHandler logHandler(LOG_LEVEL_INFO);

Khi bạn tiếp tục cuộc hành trình của mình bằng cách sử dụng DeviceOS của Particle, bạn sẽ sớm nhận ra nó có thể tiện dụng như thế nào. Bây giờ, hãy chuyển sang những thứ hay ho!

Thiết lập

Cách sử dụng hạt Argon để theo dõi vị trí

Trước tiên, chúng tôi muốn đảm bảo rằng chúng tôi đang sử dụng đúng phiên bản DeviceOS. Bất kỳ phiên bản nào sau 1.3 sẽ có Bluetooth. Bạn có thể xem hướng dẫn tại đây.

Tiếp theo, chúng tôi sẽ bắt đầu quét Ngói. Chúng tôi muốn thực hiện việc này trong loop() chức năng tại một khoảng thời gian xác định. Chúng tôi sẽ sử dụng millis() trong trường hợp này:

// Scan for devices
if( (millis() > lastSeen + TILE_RE_CHECK_MS) ){
    BLE.scan(scanResultCallback, NULL);
}

Đảm bảo rằng bạn xác định lastSeen ở đầu tệp như sau:

system_tick_t lastSeen = 0;

Chúng tôi sẽ sử dụng nó để theo dõi lần cuối cùng Ngói được "nhìn thấy". tức là lần cuối cùng Argon nhìn thấy một gói quảng cáo từ Tile.

TILE_RE_CHECK_MS có thể được định nghĩa là

#define TILE_RE_CHECK_MS 7500

Bằng cách này, chúng tôi đang kiểm tra, ở mức tối thiểu, cứ 7,5 giây một lần đối với các gói quảng cáo.

Để tìm thiết bị Tile, chúng tôi sẽ sử dụng BLE.scan . Khi chúng tôi gọi nó, Nó sẽ bắt đầu quá trình quét. Khi thiết bị được tìm thấy scanResultCallback sẽ khai hỏa.

Hiện tại, chúng ta có thể xác định scanResultCallback ở đầu tệp:

void scanResultCallback(const BleScanResult *scanResult, void *context) {
}

Bạn nhận thấy rằng nó bao gồm một BleScanResult . Điều này sẽ chứa địa chỉ, RSSI và tên thiết bị (nếu có) và thông tin dịch vụ có sẵn. Điều này sẽ hữu ích sau này khi chúng tôi đang tìm kiếm thiết bị Tile của mình!

Hãy nhớ rằng BLE.scan không quay trở lại cho đến khi quá trình quét hoàn tất. Thời gian chờ mặc định để quét là 5 giây. Bạn có thể thay đổi giá trị đó bằng cách sử dụng BLE.setScanTimeout() . setScanTimeout lấy đơn vị theo gia số 10ms. Vì vậy, thời gian chờ 500ms sẽ yêu cầu giá trị là 50.

Đối với trường hợp của ứng dụng này, tôi khuyên bạn nên sử dụng giá trị 8s (8000ms). Bạn có thể đặt nó như thế này:

BLE.setScanTimeout(800);

Trong trường hợp này, thiết bị sẽ quét trong khoảng thời gian mà nó có Tile để quảng cáo. Bằng cách đó, ít có khả năng bỏ lỡ một gói quảng cáo hơn.

Xử lý kết quả quét

Cách sử dụng hạt Argon để theo dõi vị trí

Bây giờ chúng ta có scanResultCallback cho phép xác định những gì đang xảy ra bên trong.

Trước tiên, chúng tôi muốn lấy thông tin dịch vụ bên trong dữ liệu quảng cáo. Cách tốt nhất là sử dụng scanResult->advertisingData.serviceUUID . Chúng tôi sẽ chuyển vào một mảng UUID những gì sẽ được sao chép để chúng tôi sử dụng.

BleUuid uuids[4];
int uuidsAvail = scanResult->advertisingData.serviceUUID(uuids,sizeof(uuids)/sizeof(BleUuid));

Điều này sẽ điền uuids theo cách đó bạn có thể lặp lại chúng. uuidsAvail sẽ bằng với số lượng UUID có sẵn.

Trong trường hợp của chúng tôi, chúng tôi đang tìm một UUID cụ thể. Chúng tôi sẽ xác định nó ở đầu tệp:

#define TILE_UUID 0xfeed

Thông thường UUID là nhiều lâu hơn. UUID ngắn như thế này có nghĩa là nó đã được đặt trước hoặc là một phần của thông số kỹ thuật Bluetooth. Trong cả hai trường hợp, chúng tôi sẽ kiểm tra nó giống như cách chúng tôi kiểm tra phiên bản 32bit hoặc 128bit.

Vì lý do chẩn đoán, chúng tôi cũng có thể in thông tin thiết bị. Trong trường hợp này, RSSI và địa chỉ MAC của thiết bị rất hữu ích:

// Print out mac info
BleAddress addr = scanResult->address;
Log.trace("MAC: %02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
Log.trace("RSSI: %dBm", scanResult->rssi);

Cuối cùng, hãy thiết lập một vòng lặp để xem liệu thiết bị được tìm thấy có UUID hay không:

// Loop over all available UUIDs
// For tile devices there should only be one
for(int i = 0; i < uuidsAvail; i++){

    // Print out the UUID we're looking for
    if( uuids[i].shorted() == TILE_UUID ) {
        Log.trace("UUID: %x", uuids[i].shorted());

        // Stop scanning
        BLE.stopScanning();

        return;
    }
}

Chúng tôi có thể dễ dàng so sánh phiên bản "rút gọn" của UUID với TILE_UUID . Đó là một số nguyên đơn giản nên không cần các thao tác so sánh bộ nhớ phức tạp. Vì vậy, sử dụng if( uuids[i].shorted() == TILE_UUID ) hoạt động tốt.

Bạn cũng có thể sử dụng Log.trace để in ra thông tin chẩn đoán. Trong trường hợp này, chúng tôi đang sử dụng nó để in ra shorted() phiên bản của UUID.

Kiểm tra nó!

Hãy kiểm tra những gì chúng tôi có cho đến nay!

Lập trình ứng dụng cho Argon của bạn. Mở thiết bị đầu cuối và chạy particle serial monitor để xem các thông báo gỡ lỗi. Dưới đây là một ví dụ về những gì bạn có thể thấy:

0000005825 [app] TRACE: MAC: 65:C7:B3:AF:73:5C
0000005827 [app] TRACE: RSSI: -37Bm
0000005954 [app] TRACE: MAC: B3:D9:F1:F0:5D:7E
0000005955 [app] TRACE: RSSI: -62Bm
0000006069 [app] TRACE: MAC: C5:F0:74:3D:13:77
0000006071 [app] TRACE: RSSI: -62Bm
0000006217 [app] TRACE: MAC: 65:C7:B3:AF:73:5C
0000006219 [app] TRACE: RSSI: -39Bm
0000006224 [app] TRACE: MAC: B3:D9:F1:F0:5D:7E
0000006225 [app] TRACE: RSSI: -62Bm
0000006296 [app] TRACE: MAC: D7:E7:FE:0C:A5:C0
0000006298 [app] TRACE: RSSI: -60Bm
0000006299 [app] TRACE: UUID: feed

Lưu ý cách thông báo bao gồm TRACE và cả [app] ? Điều đó có nghĩa đó là một thông báo theo dõi bắt nguồn từ mã ứng dụng. Tiện dụng phải không?

Mã này nhanh chóng bị spam, đặc biệt nếu bạn đang ở trong môi trường có nhiều thiết bị Bluetooth quảng cáo. Nếu bạn đang bật và chạy Tile thì cuối cùng bạn sẽ thấy thông báo UUID: feed . Điều đó có nghĩa là Argon của bạn đã tìm thấy Ngói!

Tiếp theo, chúng ta sẽ sử dụng nút Chế độ tích hợp để "lập trình" địa chỉ của Tile vào bộ nhớ. Bằng cách đó, chúng tôi có thể lọc ra tất cả các thiết bị mà chúng tôi không quan tâm.

Thêm nút nhấn trên thiết bị

Cách sử dụng hạt Argon để theo dõi vị trí

Đầu tiên chúng ta cần tìm hiểu cách theo dõi nút Mode. Đặt cược tốt nhất, theo tài liệu là sử dụng System.on .

System.on(button_click, eventHandler);

Đối số đầu tiên là tên của sự kiện hệ thống. Trong trường hợp của chúng tôi, đó là button_click . Đối số thứ hai là một hàm xử lý sự kiện. Chúng tôi sẽ gọi nó là eventHandler bây giờ.

Bây giờ hãy tạo eventHandler

void eventHandler(system_event_t event, int duration, void* )
{

}

Quan trọng: bạn không thể sử dụng Log chức năng bên trong eventHandler . Một cách dễ dàng để kiểm tra nó là bật tắt đèn LED trên D7. Hãy thiết lập nó!

Khởi tạo đèn LED trong setup()

// Set LED pin
pinMode(D7,OUTPUT);

Sau đó, chúng ta có thể thêm cái này vào bên trong eventHandler

if( event == button_click ) {
    if( digitalRead(D7) ) {
        digitalWrite(D7,LOW);
    } else {
        digitalWrite(D7,HIGH);
    }
}

Sau đó, chúng tôi có thể ghi vào D7 (đèn LED màu xanh dương trên bo mạch). Chúng tôi thậm chí có thể sử dụng digitalRead để đọc trạng thái của đèn LED. Nó sẽ phản hồi bằng HIGH hoặc LOW tùy thuộc vào tình huống.

Tải chương trình cơ sở vào thiết bị và chúng tôi sẽ kiểm soát tốt đèn LED màu xanh lam!

Trong phần tiếp theo, chúng ta sẽ sử dụng nút Chế độ để đưa thiết bị vào chế độ "học tập". Điều này sẽ cho phép chúng tôi thực hiện thiết lập một lần chạm với thiết bị Tile đích.

Lưu trữ Địa chỉ vào EEPROM

Cách sử dụng hạt Argon để theo dõi vị trí

Trong bước tiếp theo này, chúng tôi sẽ lưu trữ địa chỉ của Tile vào EEPROM. Bằng cách đó, khi thiết bị được khởi động lại hoặc mất nguồn, chúng tôi vẫn có thể xác định được Ô sau này.

Tuy nhiên, có một câu hỏi kéo dài. Làm cách nào để chúng tôi lưu địa chỉ ngay từ đầu?

Bằng cách theo dõi thao tác nhấn nút, chúng ta có thể đưa thiết bị vào chế độ "học". Thiết bị sẽ quét tìm một Ngói và lưu địa chỉ nếu tìm thấy.

Đầu tiên, hãy thêm một điều kiện trong if( uuids[i].shorted() == TILE_UUID ) :

// If we're in learning mode. Save to EEPROM
if( isLearningModeOn() ) {
    searchAddress = scanResult->address;
    EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
    setLearningModeOff();
}

Chúng tôi sẽ sử dụng trạng thái của D7 như một cách để biết chúng tôi đang ở "chế độ học tập". Chúng tôi thực hiện việc này bằng cách đọc D7 sử dụng digitalRead(D7) . Hãy tạo một hàm làm cho điều này rõ ràng hơn:

bool isLearningModeOn() {
    return (digitalRead(D7) == HIGH);
}

Chúng tôi cũng có thể thay thế digitalWrite(D7,LOW);digitalWrite(D7,HIGH); với các chức năng tương tự. Bằng cách đó, nó sẽ dễ dàng hơn về những gì chúng tôi đang làm.

// Set "Learning mode" on
void setLearningModeOn() {
    digitalWrite(D7,HIGH);
}

// Set "Learning mode" off
void setLearningModeOff() {
    digitalWrite(D7,LOW);
}

Sau đó, chúng tôi gán một biến toàn cục searchAddress như kết quả quét. Chúng tôi thiết lập searchAddress như thế này ở đầu tệp:

BleAddress searchAddress;

Tiếp theo, chúng tôi muốn lưu nó vào bộ nhớ không bay hơi bằng cách sử dụng EEPROM.put . TILE_EEPROM_ADDRESS được định nghĩa là 0xa . Bạn có thể xác định TILE_EEPROM_ADDRESS để sử dụng bất kỳ địa chỉ bộ nhớ nào làm bạn thích thú. Đây là định nghĩa đầy đủ được đặt ở đầu tệp.

#define TILE_EEPROM_ADDRESS 0xa

Cuối cùng, chúng tôi tắt đèn LED và "chế độ học tập" bằng cách sử dụng setLearningModeOff()

Mỗi khi tìm thấy một thiết bị, chúng tôi sẽ sử dụng millis() để đặt lastSeen . Ngoài ra, chúng tôi có thể theo dõi RSSI cuối cùng bằng cách sử dụng lastRSSI . Đó là một cách rẻ để biết gần đúng mức độ gần của thiết bị. Chúng tôi sẽ sử dụng scanResult->rssi để lấy thông tin này và đặt nó thành lastRSSI biến.

Nhìn chung, các thay đổi của bạn sẽ trông giống như sau:

...

// Print out the UUID we're looking for
if( uuids[i].shorted() == TILE_UUID ) {
    Log.trace("UUID: %x", uuids[i].shorted());

    // If we're in learning mode. Save to EEprom
    if( isLearningModeOn() ) {
        searchAddress = scanResult->address;
        EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
        setLearningModeOff();
    }

    // Save info
    lastSeen = millis();
    lastRSSI = scanResult->rssi;

    // Stop scanning
    BLE.stopScanning();

    return;
}

Trước chức năng này, chúng tôi có thể lọc ra các thiết bị không khớp với searchAddress của chúng tôi . Thêm phần sau vào trước if( uuids[i].shorted() == TILE_UUID ) :

// If device address doesn't match or we're not in "learning mode"
if( !(searchAddress == scanResult->address) && !isLearningModeOn() ) {
    return;
}

Thao tác này sẽ bỏ qua các thiết bị không khớp. Quá trình này sẽ chỉ tiếp tục nếu địa chỉ khớp hoặc chúng tôi đang ở "chế độ tìm hiểu".

Bây giờ, để chúng tôi tải searchAddress khi khởi động, chúng tôi sẽ phải tải nó từ flash. Thêm dòng này vào setup(): của bạn

EEPROM.get(TILE_EEPROM_ADDRESS, searchAddress);

Sau đó, kiểm tra để đảm bảo địa chỉ hợp lệ. Nó sẽ không hợp lệ nếu tất cả các byte là 0xFF :

// Warning about address
if( searchAddress == BleAddress("ff:ff:ff:ff:ff:ff") ) {
    Log.warn("Place this board into learning mode");
    Log.warn("and keep your Tile near by.");
}

Chúng tôi sẽ có thể "dạy" cho Argon của chúng tôi địa chỉ của Ngói của chúng tôi. Hãy thử nó ra!

Kiểm tra nó.

Bây giờ nếu chúng ta biên dịch và chạy ứng dụng, hãy để ý xem không có đầu ra nhật ký nào nữa? Chúng ta phải "dạy" địa chỉ Ngói cho Thiết bị Hạt. Vì vậy, hãy nhấn vào nút chế độ. Đèn LED màu xanh lam sẽ bật.

Sau khi tìm thấy Tile của bạn, đèn LED sẽ tắt và bạn sẽ thấy một số đầu ra trên dòng lệnh. Tương tự như những gì chúng ta đã thấy trước đây:

0000006296 [app] TRACE: MAC: D7:E7:FE:0C:A5:C0
0000006298 [app] TRACE: RSSI: -60Bm
0000006299 [app] TRACE: UUID: feed

Thiết bị đã được cam kết với bộ nhớ!

Bạn cũng có thể kiểm tra xem nó có còn được lưu sau khi đặt lại hay không. Nhấn đặt lại và kiểm tra đầu ra tương tự như trên. Nếu nó hiển thị, chúng tôi vẫn tốt!

Cập nhật Đám mây

Cách sử dụng hạt Argon để theo dõi vị trí

Cuối cùng, hãy thiết lập một hàm có tên là checkTileStateChanged . Chúng tôi sẽ sử dụng nó để kiểm tra các thay đổi đối với trạng thái của Tile một cách thường xuyên.

bool checkTileStateChanged( TilePresenceType *presence ) {

}

Mục đích chính của hàm này là so sánh lastSeen biến với thời lượng "timeout". Trong trường hợp của chúng tôi, khoảng thời gian chờ của chúng tôi là TILE_NOT_HERE_MS sẽ được đặt thành

#define TILE_NOT_HERE_MS 30000

gần đầu chương trình của bạn. Ngoài ra còn có hai điều kiện khác để tìm kiếm. Một nơi lastSeen bằng 0. Điều này thường là do ứng dụng vẫn chưa tìm thấy Tile sau khi khởi động.

Trường hợp cuối cùng sẽ là nếu thiết bị đã được nhìn thấy và lastSeen không phải là 0. Vì vậy, trong checkTileStateChanged chúng ta hãy kết hợp mọi thứ lại với nhau.

// Check to see if it's here.
if( millis() > lastSeen+TILE_NOT_HERE_MS ) {

} else if ( lastSeen == 0 ) {

} else {

}

return false;

Bây giờ chúng tôi chỉ muốn hàm này trả về true nếu trạng thái đã thay đổi . Vì vậy, chúng tôi sẽ cần tận dụng TilePresenceType con trỏ trong thỏa thuận.

TilePresenceType chỉ đơn giản là một bảng liệt kê tất cả các trạng thái có thể có. Bạn cũng có thể dán nó ở đầu tệp của mình. Đây rồi:

typedef enum {
    PresenceUnknown,
    Here,
    NotHere
} TilePresenceType;

Bạn cũng sẽ cần một biến toàn cục mà chúng ta có thể chuyển cho hàm. Đặt cái này ở đầu tệp của bạn:

// Default status
TilePresenceType present = PresenceUnknown;

Bây giờ, chúng ta có thể so sánh ở từng giai đoạn. Nó có đáp ứng các tiêu chí không? Trạng thái có khác so với trạng thái vừa rồi không? Nếu vậy, hãy trả về true.

Hãy nhớ rằng, chúng tôi sẽ muốn đặt presence sang giá trị cập nhật mới. Vì vậy, mỗi điều kiện nên cập nhật giá trị hiện diện. Ví dụ:

*presence = NotHere;

Đây là giao diện của chức năng được xả hoàn toàn:

bool checkTileStateChanged( TilePresenceType *presence ) {

    // Check to see if it's here.
    if( millis() > lastSeen+TILE_NOT_HERE_MS ) {
        if( *presence != NotHere ) {
            *presence = NotHere;
            Log.trace("not here!");
            return true;
        }
    // Case if we've just started up
    } else if ( lastSeen == 0 ) {
        if( *presence != PresenceUnknown ) {
            *presence = PresenceUnknown;
            Log.trace("unknown!");
            return true;
        }
    // Case if lastSeen is < TILE_NOT_HERE_MS
    } else {
        if( *presence != Here ) {
            *presence = Here;
            Log.trace("here!");
            return true;
        }
    }

    return false;
}

Bây giờ chúng ta có thể sử dụng chức năng này trong vòng lặp chính bên dưới bộ đếm thời gian để bắt đầu Ble.scan() . Chúng tôi có thể sử dụng nó để gửi tải trọng JSON. Trong trường hợp này, chúng tôi sẽ bao gồm thông tin quan trọng như Địa chỉ Bluetooth, lastSeen dữ liệu, lastRSSI dữ liệu và tin nhắn.

// If we have a change
if( checkTileStateChanged(&present) ) {

}

Chúng tôi sẽ sử dụng một mảng char để lấy địa chỉ của chúng tôi ở định dạng chuỗi. Bạn có thể xâu chuỗi lại với nhau toString() với toCharArray để có được những gì chúng ta cần.

// Get the address string
char address[18];
searchAddress.toString().toCharArray(address,sizeof(address));

Một chuỗi trọng tải mẫu có thể trông giống như sau:

// Create payload
status = String::format("{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}",
    address, lastSeen, lastRSSI, messages[present]);

status chỉ đơn giản là một Chuỗi được xác định ở đầu tệp:

// The payload going to the cloud
String status;

Bạn nhận thấy rằng cũng có một biến được gọi là messages . Đây là một mảng chuỗi const tĩnh. Chúng được ánh xạ tới các giá trị từ TilePresenceType . Đây là những gì nó trông như thế nào

const char * messages[] {
    "unknown",
    "here",
    "not here"
};

Bằng cách đó PresenceUnknown khớp với "unknown" , Here khớp với "here" , v.v. Đó là một cách dễ dàng rẻ tiền để liên kết một chuỗi với một enum.

Cuối cùng, chúng tôi sẽ xuất bản và xử lý. Điều này cho phép chúng tôi gửi bản cập nhật ngay lập tức.

// Publish the RSSI and Device Info
Particle.publish("status", status, PRIVATE, WITH_ACK);

// Process the publish event immediately
Particle.process();

Hàm tổng thể cuối cùng sẽ trông giống như thế này:

// If we have a change
if( checkTileStateChanged(&present) ) {

    // Get the address string
    char address[18];
    searchAddress.toString().toCharArray(address,sizeof(address));

    // Create payload
    status = String::format("{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}",
        address, lastSeen, lastRSSI, messages[present]);

    // Publish the RSSI and Device Info
    Particle.publish("status", status, PRIVATE, WITH_ACK);

    // Process the publish event immediately
    Particle.process();

}

Bây giờ, hãy thử nghiệm nó!

Đang kiểm tra!

Cách sử dụng hạt Argon để theo dõi vị trí

Chúng tôi có thể kiểm tra để đảm bảo các sự kiện Publish của chúng tôi đang diễn ra mà không có sự kiện rời khỏi Particle Workbench. Mở một thiết bị đầu cuối mới bằng cách đi tới Xem → Thiết bị đầu cuối. Sau đó sử dụng lệnh sau:

particle subscribe --device <device_name> <event_name>

Thay thế <device_name> với tên hoặc ID của thiết bị của bạn.

Thay thế <event_name> với tên của sự kiện. Trong trường hợp của chúng tôi, đó là status .

Sau đó, bạn có thể kiểm tra tất cả bằng cách tháo pin và chờ cảnh báo "không có ở đây". Cắm lại pin và bạn sẽ nhận được cảnh báo "tại đây".

Đây là một ví dụ về đầu ra

> particle subscribe --device hamster_turkey status

Subscribing to "status" from hamster_turkey's stream
Listening to: /v1/devices/hamster_turkey/events/status
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40154002,\"lastRSSI\":-82,\"status\":\"not here\"}","ttl":60,"published_at":"2019-09-07T02:29:42.232Z","coreid":"e00fce68d36c42ef433428eb"}
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40193547,\"lastRSSI\":-83,\"status\":\"here\"}","ttl":60,"published_at":"2019-09-07T02:29:50.352Z","coreid":"e00fce68d36c42ef433428eb"}

Định cấu hình Webhook

Trong phần cuối của hướng dẫn này, chúng tôi sẽ thiết lập thông báo đẩy bằng cách sử dụng webhook. Như đã đề cập trước đây, chúng tôi sẽ sử dụng Pushover và API tiện dụng của họ để gửi (các) thông báo đẩy tới (các) thiết bị mà bạn chọn.

Pushover có một API cực kỳ dễ sử dụng. Ứng dụng của họ là một con dao quân đội Thụy Sĩ dành cho các tình huống mà bạn không muốn viết mã một ứng dụng để gửi thông báo đẩy.

Điều đầu tiên bạn sẽ phải lưu ý là khóa người dùng của bạn. Bạn có thể nhận được điều đó bằng cách đăng nhập vào Pushover. Lưu ý:trước tiên bạn cần thiết lập một tài khoản nếu chưa có.

Nó sẽ trông giống như thế này:

Cách sử dụng hạt Argon để theo dõi vị trí

Nếu bạn đã đăng nhập và không thấy trang này, hãy nhấp vào biểu trưng Pushover và điều đó sẽ đưa bạn trở lại.

Tiếp theo, chúng tôi sẽ tạo một ứng dụng. Nhấp vào Ứng dụng &Plugin ở đầu màn hình.

Cách sử dụng hạt Argon để theo dõi vị trí

Sau đó, bạn nên nhấp vào Tạo ứng dụng mới. Điều này sẽ cho phép chúng tôi nhận được Mã thông báo API sẽ cần thiết trong quá trình thiết lập Particle Webhook.

Cách sử dụng hạt Argon để theo dõi vị trí

Đặt tên khi bạn thấy phù hợp. Điền vào mô tả nếu bạn muốn được nhắc nhở. Nhấp vào hộp và sau đó nhấp vào Tạo ứng dụng.

Bạn nên chuyển sang trang tiếp theo. Sao chép và lưu Mã / Khóa API chúng tôi cũng sẽ cần điều này trong một vài bước.

Cách sử dụng hạt Argon để theo dõi vị trí

Bây giờ, hãy thiết lập Webhook. Chuyển đến https://console.particle.io và tạo một tích hợp mới.

Cách sử dụng hạt Argon để theo dõi vị trí

Chúng tôi sẽ đặt Tên sự kiện sang trạng thái .

URL tới https://api.pushover.net/1/messages.json

Ngoài ra, nếu bạn muốn lọc theo một thiết bị cụ thể, hãy đảm bảo bạn chọn thiết bị đó trong Trình đơn thả xuống thiết bị.

Trong Cài đặt nâng cao chúng ta sẽ hoàn thành bằng cách thiết lập một vài trường.

Cách sử dụng hạt Argon để theo dõi vị trí

Tạo các trường sau: mã thông báo, người dùng , tiêu đề tin nhắn . Sau đó, đặt mã thông báo thành Mã thông báo API chúng tôi đã sớm hơn. Làm tương tự đối với Khóa người dùng.

Tiêu đề sẽ hiển thị dưới dạng tiêu đề của tin nhắn của bạn. Hãy biến nó thành bất cứ điều gì có ý nghĩa đối với bạn.

Bạn có thể đặt thông báo dưới dạng The Tile is currently {{{status}}}. RSSI: {{{lastRSSI}}} .

Chúng tôi đang sử dụng các mẫu ria mép ở đây. Chúng cho phép bạn sử dụng dữ liệu trong tải trọng đã xuất bản và định dạng lại nó theo ý muốn của bạn. Trong trường hợp của chúng tôi, chúng tôi đang sử dụng chúng để "điền vào chỗ trống." Tin nhắn khi được xử lý sẽ trông giống như sau:

The Tile is currently here. RSSI: -77

Lưu ý thêm, tôi sẽ nói thêm về các mẫu này trong hướng dẫn của mình. Vì vậy, hãy theo dõi điều đó!

Kiểm tra nó

Khi tích hợp của bạn đã sẵn sàng, bạn có thể kiểm tra việc thực hiện những gì chúng tôi đã làm trong bước trước đó. Tháo pin và đợi thông báo "không có ở đây". Đặt nó lại và đợi thông báo "tại đây".

Đây là giao diện của nó trên iPhone:

Cách sử dụng hạt Argon để theo dõi vị trí

Như bạn có thể thấy, tôi đã thử nghiệm nó một loạt! ?

Nếu bạn đã tiến xa đến mức này và mọi thứ đang hoạt động, thì rất tốt. Giờ đây, bạn có một công cụ theo dõi Tile cho ngôi nhà, văn phòng của bạn hoặc bất cứ nơi nào.

Tìm kiếm mã đã hoàn thành cho ví dụ này? Tôi cũng vậy! Nó được lưu trữ trên Github và có sẵn ở đây.

Kết luận

Như bạn có thể tưởng tượng, các kỹ thuật và công nghệ được sử dụng trong bài viết này có thể được sử dụng theo nhiều cách. Hãy tóm tắt một số chìa khóa quan trọng:

  1. Sử dụng Trung tâm Bluetooth để quét và xác định một thiết bị Tile có sẵn
  2. Lưu trữ thông tin nhận dạng Tile vào EEPROM. Bằng cách đó, nó có thể được truy xuất khi khởi động.
  3. Sử dụng Particle.publish quen thuộc của chúng tôi để đẩy các bản cập nhật lên đám mây.
  4. Sử dụng Webhook tích hợp hạt để tạo thông báo đẩy khi thay đổi trạng thái.

Bây giờ bạn đã có tất cả hoạt động, hãy mở rộng nó, hack nó và biến nó thành của bạn. Oh và đừng quên chia sẻ! Tôi rất muốn nghe từ bạn. hello@jaredwolff.com

Như bài đăng này? Nhấp vào một trong các liên kết chia sẻ bên dưới và chia sẻ nó với mọi người. :)

Đây là một bài đăng chéo từ blog của tôi. Bạn có thể xem bản gốc tại đây.

Quan tâm đến việc tìm hiểu thêm? Tôi đang viết một hướng dẫn về cách tận dụng tối đa Nền tảng hạt. Tìm hiểu thêm về nó tại đây.