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 hours4,981
LoRa-Tooth: Small BLE Sensors Over WiFi & LoRa Gateways

Things used in this project

Hardware components

nRF51822 small module
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

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 • 126 followers
I'm interested in approaches to IoT projects that maximize the number of people who can make things.
Contact

Comments