From 79de6590494bc06ea30a53d05b993070c30a0086 Mon Sep 17 00:00:00 2001 From: Tavis Date: Tue, 7 Nov 2023 22:47:44 -1000 Subject: [PATCH 1/2] add mqtt adafruit io example doc --- docs/software/mqtt/adafruit-io.mdx | 174 +++++++++++++++++++++++++++++ docs/software/mqtt/index.mdx | 2 + 2 files changed, 176 insertions(+) create mode 100644 docs/software/mqtt/adafruit-io.mdx diff --git a/docs/software/mqtt/adafruit-io.mdx b/docs/software/mqtt/adafruit-io.mdx new file mode 100644 index 00000000..641158a2 --- /dev/null +++ b/docs/software/mqtt/adafruit-io.mdx @@ -0,0 +1,174 @@ +--- +id: adafruit-io +title: Adafruit IO +sidebar_label: Adafruit IO +sidebar_position: 5 +--- + +### Adafruit IO for Meshtastic + +Adafruit IO can be used to graph telemetry and messages from a Meshtastic network via json/mqtt. The following example script will listen for node packets and publish voltage, rssi, snr and messages to individual feeds on adafruit IO. If a feed doesn't exist it will be created. Be aware, however, that the free Adafruit account is limited to 10 feeds. Once your feeds are being populated with data you can create dashboards to display graphs and gauges with the data. + +:::info + +To utilize this script you need to have an Adafruit IO account, a working mqtt broker setup and a mesh node that is publishing to the mqtt broker. + +::: + +You will need to modify the script with your Adafruit IO and mqtt credentials and mqtt publisher node id + +```python +# Persistent mqtt client, watch for voltage, teleme, message packets and publish them to io +# feeds will be created. free tier maxes out at 10 + +# Import Adafruit IO REST client. +from Adafruit_IO import Client, Feed, Data, RequestError +from datetime import datetime +import paho.mqtt.client as mqtt +import os +import sys +import json +import time +import random + +import pytz +# set your timezone here +timezone = pytz.timezone("US/Hawaii") + +# set your Adafruit IO creds here +AIO_USER = "tavdog" +AIO_KEY = "XXXXXXXXXXXXX" + +# set your MQTT broker information +MQTT_SERVER = "XXXXXXXXXX" +MQTT_PORT = 1883 # default +MQTT_TOPIC_PREFIX = "mesh" # specified when you setup your node to publish mqtt +MQTT_USERNAME = "xxxxxxxxx" +MQTT_PASSWORD = "xxxxxxxxx" + +# your node ID that is publishingn to the MQTT broker +MQTT_NODE_ID = "!387e0248" +# your channel (node must be set to json output) +MQTT_CHANNEL = "LongFast" + +print("\n\n") +client_id = str(random.randint(0, 100)) +mqttClient = mqtt.Client("python_mesh_client_%s" % client_id) # this needs to be kind of unique. mqtt broker will not allow duplicate connections. +mqttClient.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) +mqttClient.connect(MQTT_SERVER, MQTT_PORT) +mqttClient.loop_start() +print("Subscribing to %s/2/json/%s/%s" % (MQTT_TOPIC_PREFIX, MQTT_CHANNEL,MQTT_NODE_ID)) +mqttClient.subscribe("%s/2/json/%s/%s" % (MQTT_TOPIC_PREFIX, MQTT_CHANNEL,MQTT_NODE_ID)) +time.sleep(1) + +# you can add more channels here +#mqttClient.subscribe("%s/2/json/MauiMesh/%s" % (MQTT_TOPIC_PREFIX, MQTT_NODE_ID)) + + +aio = Client(AIO_USER, AIO_KEY) + +node_db = dict() +# bootstrap your node_db here if you want. otherwise it will populate eventually but die on restart. +# node_db = { 634792740: 'Tavis Blue', +# 947782216: 'G1 Wailuku', +# 1839130823: 'Giggle Hill', +# 2330585902: 'Ayla Kekona', +# 634717328: 'Nani Hoku', +# 3667835576: 'Rachael'} + +def get_feed(full_name,kind): + name = full_name.split('-')[0] + try: + feed = aio.feeds(f"mesh.{name.lower()}-{kind}") + except: + print("creating feed:" + kind) + # Create Feed + new_feed = Feed(name=f"{name}_{kind}") + feed = aio.create_feed(feed=new_feed,group_key="mesh") + + return feed + +def publish_rssi(data,metadata): + name = node_db[data['from']] + feed = get_feed(name,"rssi") # use a function here because we will create the feed if it doens't exist already. + print(feed.key + " \t\t: " + str(data['rssi'])) + aio.send_data(feed.key, data['rssi'],metadata) + +def publish_snr(data,metadata): + name = node_db[data['from']] + feed = get_feed(name,"snr") # use a function here because we will create the feed if it doens't exist already. + print(feed.key + " \t\t: " + str(data['snr'])) + aio.send_data(feed.key, data['snr'],metadata) + +def publish_voltage(data,metadata): + name = node_db[data['from']] + feed = get_feed(name,"voltage") # use a function here because we will create the feed if it doens't exist already. print(feed.key + " \t: " + str(data['payload'].get('voltage',"none"))) + print(feed.key + " \t: " + str(data['payload']['voltage'])) + aio.send_data(feed.key, data['payload'].get('voltage',0),metadata) + +def publish_packet(data): + + feed = aio.feeds("mesh.messages") + if (data['from'] in node_db): + data['fname'] = node_db[data['from']] + # trim down the data. we really only want to see the message content + trimmed = { + 'from' : data.get('fname',None) or data.get('from'), + 'message' : data['payload']['text'], + 'stamp' : datetime.fromtimestamp(data['timestamp'],timezone).strftime('%Y-%m-%d %H:%M:%S'), + } + aio.send_data(feed.key, json.dumps(trimmed, indent=4)) + + +def on_message(client, userdata, message): + print("\n") + print("message received " ,str(message.payload.decode("utf-8"))) + print("\n") + data = json.loads(str(message.payload.decode("utf-8"))) + + # check the topic of the message + if data['type'] == "text": + # publish all message packets to the packet log + publish_packet(data) + + # update node_db if needed + if data['type'] == 'nodeinfo': + # add to the node_db if we haven't seen it before + if data['from'] not in node_db: + node_db[data['from']] = data['payload']['shortname'] + '-' + data['payload']['longname'] + print(str(node_db)) + return # don't publish data from nodedb packets. + + # "payload":{"altitude":113,"latitude_i":208759687,"longitude_i":-1565037665 + metadata = None + if data['type'] == 'position': + metadata = { + 'lat': data['payload']['latitude_i'] / 10000000, #40.726190, + 'lon': data['payload']['longitude_i'] / 10000000, #-74.005334, + 'ele': data['payload'].get('altitude',None), + 'created_at': datetime.now(timezone), + } + # add to the node_db if we know who they are already + + + if data['from'] in node_db: + try: + if 'rssi' in data and data['rssi'] != 0: + # do the doings + publish_rssi( data, metadata ) + if 'snr' in data and data['snr'] != 0: + publish_snr( data, metadata ) + if 'payload' in data and data['payload'].get('voltage',0) != 0: + publish_voltage( data, metadata ) + except Exception as e: + print("Error sending to IO:", str(e)) + + +mqttClient.on_message = on_message + +# loop forever +while(True): + pass + +``` + diff --git a/docs/software/mqtt/index.mdx b/docs/software/mqtt/index.mdx index 2150ca5d..8242a0f5 100644 --- a/docs/software/mqtt/index.mdx +++ b/docs/software/mqtt/index.mdx @@ -142,3 +142,5 @@ An existing public [MQTT broker](https://mosquitto.org) will be the default for - [Using MQTT with Node-RED](/docs/software/mqtt/nodered.mdx) - [Using MQTT with Home Assistant](/docs/software/mqtt/home-assistant.mdx) + +- [Using MQTT with Adafruit IO](/docs/software/mqtt/adafruit-io.mdx) \ No newline at end of file From cb90168b932fe08489e9d8f415e65ae5c6661860 Mon Sep 17 00:00:00 2001 From: jopdyke <111011098+jopdyke@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:46:42 -0500 Subject: [PATCH 2/2] Update index.mdx added US distributor "Rokland" for the T-beam Supreme L76K & NEO-M10S --- docs/hardware/devices/tbeam/index.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/hardware/devices/tbeam/index.mdx b/docs/hardware/devices/tbeam/index.mdx index 34ca8a73..312baef7 100644 --- a/docs/hardware/devices/tbeam/index.mdx +++ b/docs/hardware/devices/tbeam/index.mdx @@ -232,6 +232,8 @@ This is an earlier version of the T-Beam board. Due to changes in the design thi - Firmware file: `firmware-tbeam-s3-core-X.X.X.xxxxxxx.bin` - Purchase Link: [AliExpress](https://www.aliexpress.com/item/1005005418286231.html) + - US Distributor - Purchase link: Rokland [NEO-M10S](https://store.rokland.com/products/lilygo-t-beam-supreme-esp32-s3-lora-development-board-sx1262-915mhz-gps-l76k-or-u-blox?variant=41051191378003), [Quectel L76K](https://store.rokland.com/products/lilygo-t-beam-supreme-esp32-s3-lora-development-board-sx1262-915mhz-gps-l76k-or-u-blox?variant=41051191345235) + ![T-Beam Supreme](/img/hardware/T-BEAM-S3-Supreme.jpg)