Eric Tsai
Published © Apache-2.0

LoRa-Tooth: Small BLE Sensors Over WiFi & LoRa Gateways

Small, cheap, low-powered sensors are still a challenge to make. LoRa-Tooth uses $6 BLE modules to make untethered sensors with long range.

IntermediateFull instructions provided10 hours8,612

Things used in this project

Hardware components

nRF51822 Bluetooth Smart Beacon Kit
Nordic Semiconductor nRF51822 Bluetooth Smart Beacon Kit
This is a 8-pin nRF51822 BLE module. Used for many sensor examples. https://www.aliexpress.com/item/1pc-Nordic-BLE-sensor-nRF51822-2-4G-wireless-module-for-Xbee-ble4-0-small-size-SMD/32704439466.html?spm=2114.search0104.3.29.2c71678ddaeM3c&ws_ab_test=searchweb0_0,searchweb201602_5_10152_10151_10065_10344_10130_10068_10324_10547_10342_10325_10546_10343_10340_10548_10341_10545_10696_10084_10083_10618_10307_10059_308_100031_10103_10624_10623_10622_10621_10620,searchweb201603_55,ppcSwitch_5&algo_expid=23355128-d72c-4cfa-8db0-0f90afd4a8b3-7&algo_pvid=23355128-d72c-4cfa-8db0-0f90afd4a8b3&transAbTest=ae803_2&priceBeautifyAB=0
×1
NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
Any of those $4 NodeMCU ESP8266-12E will work.
×1
Adafruit 32U4 LoRa Module
Or clone from ebay/Aliexpress
×1
41x41x15mm enclosure
https://www.aliexpress.com/item/6-pieces-a-lot-hand-held-plastic-enclosures-41-41-15mm-1-6-1-6-0/1711584798.html?spm=2114.search0104.3.52.733a9152unvCg4&ws_ab_test=searchweb0_0,searchweb201602_3_10152_10151_10065_10344_10130_10068_10324_10547_10342_10325_10546_10343_10340_10548_10341_10545_10696_10084_10083_10618_10307_10059_100031_10103_10624_10623_10622_10621_10620,searchweb201603_55,ppcSwitch_4&algo_expid=a721f77c-1d91-4f16-af7e-fd13ad83db77-7&algo_pvid=a721f77c-1d91-4f16-af7e-fd13ad83db77&priceBeautifyAB=0
×1
nRF51822 purple w/ LIS3DH
This is the BLE module with an integrated low power acceleration sensor, perfect for orientation and motion sensing. Use for dog-on-couch sensor, or to monitor garage door open/close, or washer/dryer completion. https://www.ebay.com/itm/Nrf51822-LIS3DH-Bluetooth-Module-Development-board-NEW/222196941463?hash=item33bbf84297:g:2kwAAOSwZVlXlHoQ
×1
51x51x20mm enclosure
https://www.aliexpress.com/item/10pcs-lot-injected-junction-box-IP54-ABS-plastic-enclosure-project-box-for-electronic-device-box-51/32754606612.html?spm=a2g0s.9042311.0.0.27424c4dyTSxcl
×1
cr2032 coin cell battery holder
https://www.aliexpress.com/item/20pcs-White-Housing-CR2032-SMD-Cell-Button-Battery-Holder-Socket-Case/32823937537.html?spm=2114.search0104.3.29.4d285a31z9Xbe9&ws_ab_test=searchweb0_0,searchweb201602_1_10152_10151_10065_10344_10068_10130_10324_10342_10547_10325_10343_10546_5722611_10340_10548_10341_10545_10696_5722911_5722811_5722711_10084_10083_10618_10307_10059_306_100031_10103_10624_10623_10622_10621_10620_5722511,searchweb201603_1,ppcSwitch_5&algo_expid=55bbbdd0-2f33-499a-97de-68023b3d1637-4&algo_pvid=55bbbdd0-2f33-499a-97de-68023b3d1637&priceBeautifyAB=0
×1

Story

Read more

Schematics

mbed binary for BLE Gateway

Use this binary directly to load into nRF51822 to act as BLE gateway.

Code

Items file for OpenHAB examples

JSON
//ble items
Number door1 "Front Door[MAP(window.map):%s]" (ALL) {mqtt="<[mymosquitto:/+/+/e1cba36307c0/mag:state:default]"}
Number window1 "Window[MAP(window.map):%s]" (ALL) {mqtt="<[mymosquitto:/+/+/c38abd3fac90/mag:state:default]"}
Number itm_temp_E4 "Temperature Livingroom [%.1fF]" (All) {mqtt="<[mymosquitto:/+/+/c9f14ebbddfd/TMP/#:state:default]"}
Number itm_temp_2E "Temperature Basement [%.1fF]" (All) {mqtt="<[mymosquitto:/+/+/df2607198d82/TMP/#:state:default]"}
Number itm_hum_2E "Humidity Basement [%.1f%%]" (All) {mqtt="<[mymosquitto:/+/+/df2607198d82/HUM/#:state:default]"}
Number itm_temp_81 "Temperature Garage [%.1fF]" (All) {mqtt="<[mymosquitto:/+/+/d0e1ede7cc81/TMP/#:state:default]"}
Number itm_hum_81 "Humidity Garage [%.1f%%]" (All) {mqtt="<[mymosquitto:/+/+/d0e1ede7cc81/HUM/#:state:default]"}
Number itm_lum_81 "Lights Garage [%.1f]" (All) {mqtt="<[mymosquitto:/+/+/d0e1ede7cc81/LUM/#:state:default]"}
Number itm_dogfood_fill "Dog Food Level [%.1f]" (All) {mqtt="<[mymosquitto:/+/+/f030822800fd/dis/#:state:default]"}
Number window2 "Window 2 [%.1f cm]" (ALL) {mqtt="<[mymosquitto:/+/+/e704d0d46e43/DIS/#:state:default]"}

Node-RED configuration for geolocation of BLE beacons

C/C++
Node-RED Flow for geolocation of BLE beacons
No preview (download only).

OpenHAB & Node-RED configuration for toy puppy motion sensing

JSON
//item def:
Number itm_shake "shake [%.1f]" (All) {mqtt="<[mymosquitto:/+/bedroom/+/shake:state:default]"}
Switch itm_shake_enb "Alarm Enable" (ALL)
Switch itm_shake_alm_sta "Dog Dog Status" <siren>



//sitemap def:
sitemap motion label="Bad Dog Alarm"
{
        Frame label="Living Room Couch"
        {
                Switch item=itm_shake_enb
                Switch item=itm_shake_alm_sta mappings=[OFF="Reset"]
        }

}


//rules
rule bad_Dog_Couch
when
    Item itm_shake received update
then
    if(itm_shake_enb.state == ON)
    {
        sendCommand(itm_shake_alm_sta, ON)
        playSound("airhorn.mp3")
    }
end

//---------------------------------------
node red:


[
    {
        "id": "2b204280.0923c6",
        "type": "mqtt in",
        "z": "9c4bfd01.0660f",
        "name": "Shake",
        "topic": "/+/+/+/shake/#",
        "qos": "0",
        "broker": "d602c15f.8da268",
        "x": 90,
        "y": 680,
        "wires": [
            []
        ]
    },
    {
        "id": "b43761a5.f9ec88",
        "type": "e-mail",
        "z": "9c4bfd01.0660f",
        "server": "smtp.gmail.com",
        "port": "465",
        "secure": true,
        "name": "toomuchiot@gmail.com",
        "dname": "email",
        "x": 490,
        "y": 760,
        "wires": []
    },
    {
        "id": "2b546666.31617a",
        "type": "mqtt in",
        "z": "9c4bfd01.0660f",
        "name": "heart button",
        "topic": "/ble/+/c2009c7e8294/but/5",
        "qos": "0",
        "broker": "d602c15f.8da268",
        "x": 110,
        "y": 760,
        "wires": [
            [
                "f6d3082b.cf2a2"
            ]
        ]
    },
    {
        "id": "f6d3082b.cf2a2",
        "type": "function",
        "z": "9c4bfd01.0660f",
        "name": "add text",
        "func": "var mynewout={payload: msg.payload};\nmynewout.payload = \"I need help!\";\nreturn mynewout;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 300,
        "y": 760,
        "wires": [
            [
                "b43761a5.f9ec88"
            ]
        ]
    },
    {
        "id": "388da59c.b7791a",
        "type": "mqtt in",
        "z": "9c4bfd01.0660f",
        "name": "left hand",
        "topic": "/ble/+/c2009c7e8294/but/7",
        "qos": "0",
        "broker": "d602c15f.8da268",
        "x": 100,
        "y": 920,
        "wires": [
            [
                "84dfb545.5c3c6"
            ]
        ]
    },
    {
        "id": "c58ad89d.0bbb28",
        "type": "mqtt in",
        "z": "9c4bfd01.0660f",
        "name": "right hand",
        "topic": "/ble/+/c2009c7e8294/but/6",
        "qos": "0",
        "broker": "d602c15f.8da268",
        "x": 100,
        "y": 860,
        "wires": [
            [
                "4f68190e.4f2fa"
            ]
        ]
    },
    {
        "id": "4f68190e.4f2fa",
        "type": "exec",
        "z": "9c4bfd01.0660f",
        "command": "/home/pi/scripts/node/lights_on.sh",
        "addpay": true,
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "oldrc": false,
        "name": "lights on",
        "x": 480,
        "y": 860,
        "wires": [
            [],
            [],
            []
        ]
    },
    {
        "id": "84dfb545.5c3c6",
        "type": "exec",
        "z": "9c4bfd01.0660f",
        "command": "/home/pi/scripts/node/lights_off.sh",
        "addpay": true,
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "oldrc": false,
        "name": "lights off",
        "x": 480,
        "y": 920,
        "wires": [
            [],
            [],
            []
        ]
    },
    {
        "id": "d602c15f.8da268",
        "type": "mqtt-broker",
        "z": "",
        "name": "MQT 1.23",
        "broker": "192.168.2.46",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "60",
        "cleansession": true,
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": ""
    }
]
--------------------------------------------------

Telegraf config

JSON
Use this configuration for Telegraf so MQTT data gets stuffed into InfluxDB
# Read metrics from MQTT topic(s)
[[inputs.mqtt_consumer]]
  ## MQTT broker URLs to be used. The format should be scheme://host:port, schema can be tcp, ssl, or ws.
  servers = ["tcp://localhost:1883"]
  ## MQTT QoS, must be 0, 1, or 2
  qos = 2
  ## Connection timeout for initial connection in seconds
  #connection_timeout = "30s"
  ## Topics to subscribe to
  topics = [
    "/+/+/+/rssi",
    "/+/+/+/mag/#",
    "/+/+/+/mag",
    "/+/+/+/xcnt/#",
    "TestResults",
  ]
  # if true, messages that can't be delivered while the subscriber is offline will be delivered when it comes back (such 
  # as on service restart). NOTE: if true, client_id MUST be set
  persistent_session = false
  # If empty, a random client ID will be generated.
  client_id = ""
  ## username and password to connect MQTT server.
  # username = "telegraf" password = "metricsmetricsmetricsmetrics"
  ## Optional SSL Config
  # ssl_ca = "/etc/telegraf/ca.pem" ssl_cert = "/etc/telegraf/cert.pem" ssl_key = "/etc/telegraf/key.pem"
  ## Use SSL but skip chain & host verification
  # insecure_skip_verify = false
  ## Data format to consume. Each data format has its own unique set of configuration options, read more about them 
  ## here: https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
  #data_format = "influx"
  data_format = "value"
###############################################################################
# Read metrics from MQTT topic(s) FLOATS
[[inputs.mqtt_consumer]]
  name_override = "mqtt_consumer_floats"
  servers = ["tcp://localhost:1883"]
  qos = 2
  #connection_timeout = "30s"
  topics = [
    "/+/+/+/volt/#",
    "/+/+/+/TMP/#",
    "/+/+/+/HUM/#",
    "/+/+/+/BEA",
    "/+/+/+/LUM/#",
    "/+/+/+/dis/#",
    "/+/+/+/DIS/#",
    "/+/dogfoodpercent",
  ]
  persistent_session = false
  client_id = ""
  # insecure_skip_verify = false data_format = "influx"
  data_format = "value"
  data_type = "float"

###############################################################################
# Read metrics from MQTT topic(s) strings
[[inputs.mqtt_consumer]]
  name_override = "mqtt_consumer_string"
  servers = ["tcp://localhost:1883"]
  qos = 2
  #connection_timeout = "30s"
  topics = [
    "/g/g/+/location/#",
  ]
  persistent_session = false
  client_id = ""
  # insecure_skip_verify = false data_format = "influx"
    # insecure_skip_verify = false data_format = "influx"
  data_format = "value"
  data_type = "string"
###############################################################################




###############################################################################
#                            OUTPUT PLUGINS #
###############################################################################
# Configuration for influxdb server to send metrics to
[[outputs.influxdb]]
  ## The full HTTP or UDP URL for your InfluxDB instance.
  ##
  ## Multiple urls can be specified as part of the same cluster, this means that only ONE of the urls will be written to 
  ## each interval.
  # urls = ["udp://127.0.0.1:8089"] # UDP endpoint example
  urls = ["http://localhost:8086"] # required
  ## The target database for metrics (telegraf will create it if not exists).
  database = "openhab_db" # required
  ## Name of existing retention policy to write to.  Empty string writes to the default retention policy.
  retention_policy = ""
  ## Write consistency (clusters only), can be: "any", "one", "quorum", "all"
  write_consistency = "any"
  ## Write timeout (for the InfluxDB client), formatted as a string. If not provided, will default to 5s. 0s means no 
  ## timeout (not recommended).
  timeout = "37s"
  # username = "telegraf"
  username = "openhab"
  # password = "metricsmetricsmetricsmetrics"
  password = "AnotherSuperbPassword456-"
  ## Set the user agent for HTTP POSTs (can be useful for log differentiation)
  user_agent = "telegraf"
  ## Set UDP payload size, defaults to InfluxDB UDP Client default (512 bytes)
  # udp_payload = 512
  ## Optional SSL Config
  # ssl_ca = "/etc/telegraf/ca.pem" ssl_cert = "/etc/telegraf/cert.pem" ssl_key = "/etc/telegraf/key.pem"
  ## Use SSL but skip chain & host verification
  # insecure_skip_verify = false
  ## HTTP Proxy Config
  # http_proxy = "http://corporate.proxy:3128"
  ## Optional HTTP headers
  # http_headers = {"X-Special-Header" = "Special-Value"}
  ## Compress each HTTP request payload using GZIP.
  # content_encoding = "gzip"

WiFi Gateway

Posts MQTT from JSON serial input

BLE-LoRa Bridge

Re-transmits BLE advertisements as LoRa packets

LoRa Gateway

Convert LoRa packet to serial JSON - use in conjunction with WiFi MQTT Gateway

LoRa GPS sender

Example LoRa sensor - use in conjunction with LoRa gateway (LoRa receiver and WiFi MQTT Gateway)

Credits

Eric Tsai

Eric Tsai

6 projects • 131 followers
I'm interested in approaches to IoT projects that maximize the number of people who can make things.

Comments