Skip to content

Instantly share code, notes, and snippets.

@boverby
Created November 17, 2024 04:33
Show Gist options
  • Save boverby/bf96c32dbf07ff946242e5d1111ead3e to your computer and use it in GitHub Desktop.
Save boverby/bf96c32dbf07ff946242e5d1111ead3e to your computer and use it in GitHub Desktop.
python espnow to mqtt gateway based on Microfire LLC data structure and clients
#!/opt/espnow/bin/python3
# https://medium.com/@potekh.anastasia/a-beginners-guide-to-mqtt-understanding-mqtt-mosquitto-broker-and-paho-python-mqtt-client-990822274923
# https://github.com/u-fire/ESPHomeComponents
# https://github.com/ChuckMash/ESPythoNOW
import sys
import paho.mqtt
import paho.mqtt.client as mqttClient
import json
import pprint
from ESPythoNOW import *
client = mqttClient.Client(mqttClient.CallbackAPIVersion.VERSION2, "beebox")
if client.connect("192.168.1.1", 1883, 60) != 0:
print("Couldn't connect to the mqtt broker at 192.168.1.1")
sys.exit(1)
def callback(from_mac, to_mac, msg):
publishNow(from_mac, msg.decode() )
print("ESP-NOW beebox saw %s to %s %s" % (from_mac, to_mac, msg.decode() ))
def publishNow( from_mac, msg ):
tokens = msg.split(':');
print (tokens);
doc = {}
macaddr = from_mac.replace(':', '').lower() # 24:EC:4A:26:91:04 to 24ec4a269104
if ( len(tokens) != 12 ):
print(" %d tokens found [bad]" % (len(tokens)) )
else:
print(" %d tokens found[good]" % (len(tokens)) )
message_type = tokens[2];
# expected binary_sensor config
# {
# "name": "now55_wakeup_cause",
# "icon": "mdi:text",
# "stat_t": "now55/sensor/now55_wakeup_cause/state",
# "uniq_id": "24ec4a269104_now55_wakeup_cause",
# "dev": {
# "ids": "24ec4a269104",
# "name": "now55",
# "sw": "2024.6.3",
# "mdl": "esp32-s3-devkitc-1",
# "mf": "espressif"
# }
# expected sensor config
# {
# "dev_cla": "temperature",
# "unit_of_meas": "°F",
# "stat_cla": "measurement",
# "name": "now55_temperature",
# "stat_t": "now55/sensor/now55_temperature/state",
# "uniq_id": "24ec4a269104_now55_temperature",
# "dev": {
# "ids": "24ec4a269104",
# "name": "now55",
# "sw": "2024.10.3",
# "mdl": "esp32-s3-devkitc-1",
# "mf": "espressif"
# }
if ( message_type == "binary_sensor"):
if ( len(tokens[3]) > 0 ):
doc['name'] = tokens[3]
if ( len(tokens[0]) != 0):
stat_t = tokens[0] + "/binary_sensor" + tokens[3] + "/state"
doc['stat_t'] =stat_t
if ( len(tokens[0]) != 0):
uniq_id = macaddr + "_" + tokens[3]
doc['uniq_id'] = uniq_id;
doc["dev"] = {}
doc["dev"]["ids"] = macaddr
if ( len(tokens[0]) != 0):
doc["dev"]["name"] = tokens[0]
doc["dev"]["sw"] = tokens[8]
doc["dev"]["mdl"] = tokens[9]
doc["dev"]["mf"] = "expressif"
# pprint.pprint(doc);
topic = "%s/binary_sensor/%s/state" % ( tokens[0], tokens[3] )
client.publish( topic, tokens[5] , 0)
config_topic = "%s/binary_sensor/%s/%s/config" % ( "homeassistant",tokens[0], tokens[3] )
json_doc = json.dumps(doc)
pprint.pprint(json_doc)
client.publish( config_topic, json_doc , 0)
else:
if ( len(tokens[1]) > 0 ):
doc['dev_cla'] = tokens[1]
if ( len(tokens[4]) > 0 ):
doc['unit_of_meas'] = tokens[4]
if ( len(tokens[2]) > 0 ):
doc['stat_cla'] = tokens[2]
if ( len(tokens[3]) > 0 ):
doc['name'] = tokens[3]
if ( len(tokens[6]) > 0 ):
icon = tokens[6] + ":" + tokens[7]
doc['icon'] = icon
if ( len(tokens[0]) > 0 ):
stat_t = tokens[0] + "/sensor/" + tokens[3] + "/state"
doc['stat_t'] = stat_t
if ( len(tokens[0]) != 0):
uniq_id = macaddr + "_" + tokens[3]
doc['uniq_id'] = uniq_id;
doc["dev"] = {}
doc["dev"]["ids"] = macaddr
if ( len(tokens[0]) != 0):
doc["dev"]["name"] = tokens[0]
doc["dev"]["sw"] = tokens[8]
doc["dev"]["mdl"] = tokens[9]
doc["dev"]["mf"] = "expressif"
doc["dev"]["ids"] = macaddr
# pprint.pprint(doc);
topic = "%s/sensor/%s/state" % ( tokens[0], tokens[3] )
client.publish( topic, tokens[5] , 0)
config_topic = "%s/sensor/%s/%s/config" % ( "homeassistant",tokens[0], tokens[3] )
json_doc = json.dumps(doc)
pprint.pprint(json_doc)
client.publish( config_topic, json_doc , 0)
# ESP-NOW beebox saw 24:EC:4A:26:91:04 to FF:FF:FF:FF:FF:FF now55:voltage:measurement:now55_vdd:V:4.05:::2024.10.3:esp32-s3-devkitc-1:sensor:
# ['now55', 'temperature', 'measurement', 'now55_temperature', '°F', '68.0', '', '', '2024.10.3', 'esp32-s3-devkitc-1', 'sensor', '']
# 12 tokens found[good]
# {'dev_cla': 'temperature',
# 'name': 'now55_temperature',
# 'stat_cla': 'measurement',
# 'stat_t': 'now55/sensor/now55_temperature/state',
# 'uniq_id': '24EC4A269104_now55_temperature',
# 'unit_of_meas': '°F'}
topic = "%s/sensor/%s/state" % ( tokens[0], tokens[3] )
client.publish( topic, tokens[5] , 0)
espnow = ESPythoNow(interface="wlp1s0", accept_all=True, callback=callback)
espnow.start()
input() # Run until enter is pressed
@boverby
Copy link
Author

boverby commented Nov 17, 2024

combining code from :
https://github.com/u-fire - esp32 inside esphome cliant and bridge
note : the bridge was unreliable for me. Tried several diff esp32, several brokers
mqtt bridge just timed out after 1-2 publishes
https://github.com/ChuckMash/ESPythoNOW - receives espnow packets with library ESPythoNOW.py

git clone https://github.com/ChuckMash/ESPythoNOW
mkdir /opt/espnow
cd /opt
python -m venv espnow
cd /opt/espnow
source /opt/espnow/bin/activate
cp ESPythoNOW/ESPythoNOW.py /opt/espnow/

pip3 install scapy
pip3 install paho-mqtt
target = ./sniffMqtt.py

used https://github.com/u-fire/ESPHomeComponents in esp32 clients

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment