Home

Awesome

SwiftyXBee

⚡️A Swift library for communicating with XBee (ZigBee Series 2) radios in API mode.

<p> <img src="https://img.shields.io/badge/Architecture%20-ARMv6%20%7C%20%20ARMv7%2F8-red.svg"/> <img src="https://img.shields.io/badge/OS-Raspbian%20%7C%20Debian%20%7C%20Ubuntu-yellow.svg"/> <a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift-4x-brightgreen.svg"/></a> <a href="https://raw.githubusercontent.com/samco182/SwiftySHT20/master/LICENSE"><img src="https://img.shields.io/badge/Licence-MIT-blue.svg" /></a> </p> <img src="https://www.digi.com/products/embedded-systems/rf-modules/2-4-ghz-modules/xbee-zigbee/product-images/xbee-s2c-zigbee" height="300" width="450">

Summary

This is a SwiftyGPIO based library for communicating with XBee radios in API mode, with support for Series 2 only.

This is a work in progress. I started coding the library for a project I am currently working on, so, as of now, it only supports ATCommand, ATCommandResponse, Tx, Rx, and Transmit Status API Frames. If you want to contribute to this noble cause, please submit a PR and I will be more than happy to review it and merge it :smile:.

For more information regarding the RF module, you can consult its datasheet.

API Mode

XBees support two operation modes: API and AT. API mode requires that the device communicate through a structured interface (that is, data is communicated in frames in a defined order). The API specifies how the device sends and receives commands, command responses, and module status messages using a serial port Data Frame. On the other hand, in AT (transparent) mode, the XBee radio simply relays serial data to the receiving XBee, as identified by the DH+DL address.

According to the documentation:

The XBee firmware supports two API operating modes: without escaped characters and with escaped characters. Use the AP command to enable either mode. To configure a device to one of these modes, set the following AP parameter values:

⚠️ This library is designed to work only in API mode, it requires the AP mode set to 2 (escape bytes), as this setting offers the best reliability.

Hardware Details

This is the pin assignment to manually connect (no XBee shield) the device to any of the compatible boards:

XBee PinBoard UART
VCC = 1VCC 3.3V
DOUT = 2RX / Receive
DIN / CONFIG = 3TX / Transmit
GND = 10GND

The UART pins on the RaspberryPi (pin 14 TXD, pin 15 RXD) need to be enabled via raspi-config before you can use them (restart required). By enabling the UART pins, you will lose the ability to access the login shell over serial.

Supported Boards

Every board supported by SwiftyGPIO: RaspberryPis, BeagleBones, C.H.I.P., etc...

To use this library, you'll need a Linux ARM board running Swift 5.x 🚗.

The examples below will use a Raspberry Pi 3B+ board, but you can easily modify the examples to use one of the other supported boards. Full working demo projects for the RaspberryPi3B+ are available under the Examples directory.

Installation

First of all, makes sure your board is running Swift 5.x ⚠️!

Since Swift 5.x supports Swift Package Manager, you only need to add SwiftXBee as a dependency in your project's Package.swift file:

let package = Package(
    name: "MyProject",
    dependencies: [
        .package(url: "https://github.com/samco182/SwiftyXBee", from: "1.0.0"),
    ]
    targets: [
        .target(
            name: "MyProject", 
            dependencies: ["SwiftyXBee"]),
    ]
)

Then run swift package update to install the dependency.

Usage

Initialization

The first thing is to initialize an instance of SwiftyXBee with the same UART configuration as the one you used to setup the XBee devices on the XCTU tool or through the AT command mode. Once you have your xbee object initialized, you can send and receive data packets between XBees:

import SwiftyXBee

let serial = SerialConnection(speed: .S9600, bitsPerChar: .Eight, stopBits: .One, parity: .None)
let xbee = SwiftyXBee(for: .RaspberryPi3, serialConnection: serial)

You can also initialize the XBee object with the following method:

import SwiftyXBee

let xbee = SwiftyXBee()

This initializer defaults to .RaspberryPi3 as the selected board and serial connection with speed: .S9600, bitsPerChar: .Eight, stopBits: .One, and parity: .None).

AT Command Packet

AT-type commands can be sent via API frames to configure your local radio. They can query the settings on the local radio or set parameters. These are all the same commands you typed in transparent/command mode.

For this example, the local radio's Node Identifier parameter is been set and read.

Setting AT Command parameter:

// The new Node Identifier
let nodeIdentifier = "XBee Test"

xbee.sendATCommand(.addressing(.ni(.write(nodeIdentifier))), frameId: .sendNoACK)

Reading AT Command parameter:

xbee.sendATCommand(.addressing(.ni(.read)))

do {
    let atCommandResponse = try xbee.readATCommandResponse()
    print("AT Command Response received: \(atCommandResponse.frameData.commandData) = \(atCommandResponse.frameData.commandData.string)")
} catch let error {
    print("Error receiving packet: \(error)")
}

Transmit Packets

There a several different types of transmit (TX) packets available. But as mentioned above, as of now, the library only allows Transmit Request packets to be sent. A list of all TX packets can be found in the API documentation. All classes that end in "Request" are TX packets.

// The destination XBee 64-bit serial number
let deviceAddress = DeviceAddress(address: 0x0013A20012345678)

// The destination XBee 16-bit network address
let networkAddress = NetworkAddress(address: 0xFFFE)

// The actual message to be sent
let message = "This is my message to send!"

xbee.sendTransmitRequest(to: deviceAddress, network: networkAddress, message: message)

When a Transmit Request completes, if configured on the request's Frame Id, the receiver device will send a Transmit Status packet out of the serial interface. This message indicates if the Transmit Request was successful or if it failed. If you want to make sure your packet was correctly delivered, call the following code:

do {
    let transmitStatus = try xbee.readTransmitStatus()
    print("Status received: \(readingPacket.frameData.deliveryStatus)")
} catch let error {
    print("Error: \(error)")
}

Receive Packet

As with transmit (TX) packets, there are also several different types of receive (RX) packets available. But as of now, the library only allows Receive Packet API frame to be read.

do {
    let readingPacket = try xbee.readRFDataPacket()
    print("Packet received: \(readingPacket.frameData.receivedData)")
} catch let error {
    print("Error: \(error)")
}

Note 🔎

If you want to better understand how ZigBee communication protocol works, or the details (in a more comprehensive way) of the most common API frames XBee counts with, you could try reading this book.