Giter Club home page Giter Club logo

lorano's Introduction

lorano   Build Status Coverage Status NPM version

High-level Node.js module for reading and writing LoRa packets, with support for over-the-air activation (OTAA) of devices.

Your application is given a single Duplex stream operating in object mode for reading and writing packets. Replying to a packet typically involves just supplying a payload, though your application can override the default transmission settings if required.

Tested on a Raspberry Pi 3 Model B with an IMST iC880A-SPI.

API documentation is available here.

Example

This program works in conjunction with a corresponding Arduino sketch (tested on a SODAQ Explorer).

It reads 12 byte packets from the LoRa radio, leaves the first 6 bytes unchanged and randomizes the randomizes the last 6 bytes. It then sends the packet back to the radio. The Explorer does the same but randomizes the first 6 byes it receives, leaving the last 6 bytes unchanged.

Each side then checks whether it gets back the bytes it randomized in the previous packet it sent.

example.js
const path = require('path');
const crypto = require('crypto');
const { Link } = require('lorano');
const lora_comms = require('lora-comms');
const { Model } = require('objection');

// Start radio
process.on('SIGINT', lora_comms.stop);
lora_comms.start_logging();
lora_comms.log_info.pipe(process.stdout);
lora_comms.log_error.pipe(process.stderr);
lora_comms.start();

// Connect to database
const knex = require('knex')({
    client: 'sqlite3',
    useNullAsDefault: true,
    connection: {
        filename: path.join(__dirname, 'lorano.sqlite3')
    }
});
Model.knex(knex);

const link = new Link(Model, lora_comms.uplink, lora_comms.downlink, {
    // USE YOUR OWN IDS!
    appid: Buffer.alloc(8),
    netid: crypto.randomBytes(3) // 7 lsb = NwkId
});

link.on('ready', async () =>
{
    // Add device (usually you'll seed the database as a separate task)
    const nwk_addr = crypto.randomBytes(4); // 25 lsb
    nwk_addr[0] &= 0x01; // 7 msb must be 0
    await knex('OTAADevices').insert({
        // USE YOUR OWN VALUES!
        NwkAddr: nwk_addr,
        DevEUI: Buffer.from('0000000000000000', 'hex'),
        AppKey: Buffer.alloc(16)
    });

    // Receive and send packets until we get a match

    const duplex = require('awaitify-stream').createDuplexer(link);
    const payload_size = 12;
    let send_payload = crypto.randomBytes(payload_size);

    while (true) {
        const recv_data = await duplex.readAsync();
        if (recv_data === null) {
            return;
        }
        if (recv_data.payload.length !== payload_size) {
            continue;
        }
        if (recv_data.payload.equals(send_payload)) {
            // Shouldn't happen because send on reverse polarity
            console.error('ERROR: Received packet we sent');
            continue;
        }

        if (recv_data.payload.compare(send_payload,
                                      payload_size/2,
                                      payload_size,
                                      payload_size/2,
                                      payload_size) === 0) {
            console.log('SUCCESS: Received matching data');
            return lora_comms.stop();
        }

        send_payload = Buffer.concat([recv_data.payload.slice(0, payload_size/2),
                                      crypto.randomBytes(payload_size/2)]);
        recv_data.reply.payload = send_payload;
        await duplex.writeAsync(recv_data.reply);
    }
});

First you need to modify at least DevEUI with the unique identifier of your device. You can then run the example like this:

grunt example

Installation

npm install lorano

Database

In the top-level directory you’ll find a file called lorano.empty.sqlite3. This contains an empty copy of the database lorano uses to store information about your devices (addresses, keys, activation state etc).

You should use a copy of this file in your application and pass its location when setting up Knex.js. By default the database is SQLite but Knex.js supports many other databases. If you want to use a different database, use the lorano migrations to populate it and edit knexfile.js accordingly.

Seeding device data

You need to add your devices to the database otherwise lorano will ignore packets it receives from them.

Over-The-Air Activation (OTAA) devices

For each of your devices, you must add a row to the OTAADevices table containing the following columns:

  • NwkAddr: Unique network address of the device. This can be random as long as it’s unique. It must be a binary value 4 bytes long but only the 25 least significant bits are used and the 7 most significant must be 0.

  • DevEUI: Unique global device ID in the IEEE EUI64 address space. This must be a binary value 8 bytes long and can usually be quered from the hardware by calling a device API.

  • AppKey: The AES-128 key that you’ve assigned to the device for your application. This is a shared secret between your application and the device and is used to derive session keys specific for the device to encrypt and verify packets communication with it. It must be a binary value 16 bytes long.

An example of seeding the database for an OTAA device using Knex.js can be found in test/seeds/test_otaa.js.

Activation By Personalization (ABP) devices

For each of your devices, you must add a row to the ABPDevices table containing the following columns:

  • DevAddr: The identifier of your network (7 most significant bits) and the unique address of the device within it (25 least significant bits). This must be a binary value 4 bytes long.

  • NwkSKey: Network session key for the device. This is a shared secret between your application and the device and is used to calculate and verify the message integrity code of data messages. It must be a binary value 16 bytes long.

  • AppSKey: Application session key for the device. This is a shared secret between your application and the device and it used to encrypt and decrypt data messages. It must be a binary value 16 bytes long.

An example of seeding the database for an ABP device using Knex.js can be found in test/seeds/test_abp.js.

IMST iC880A-SPI reset

If you’re using an IMST iC880A-SPI, it needs to be reset after it’s powered up.

My iC880A-SPI is connected to a Pi via a backplane which brings the reset line out on GPIO 25. I run the following shell script to perform the reset:

iC880A-SPI_reset.sh
echo "25" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio25/direction
echo "1" > /sys/class/gpio/gpio25/value
sleep 5
echo "0" > /sys/class/gpio/gpio25/value
sleep 1
echo "0" > /sys/class/gpio/gpio25/value

Test

By default, the tests simulate LoRa packets and can be run with:

grunt test

If you have a LoRa device that can run test/lorano_test.ino then you can pass its DEVEUI as an argument like this:

grunt test --deveui=XXXXXXXXXXXXXXXX

I’ve tested this with a SODAQ Explorer.

Lint

grunt lint

Coverage

grunt coverage

Or with a LoRa device running test/lorano_test.ino:

grunt test --deveui=XXXXXXXXXXXXXXXX

Licence

MIT

lorano's People

Contributors

davedoesdev avatar

Watchers

 avatar  avatar

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.