thingsboard connection to esp32 using MQTT - esp32

I want to connect ESP32 to demo thingsboard using MQTT and I've used umqtt.simple to connect to it but there's a problem. Whenever I try to connect it gives me either this (File "umqtt/simple.py", line 99, in connect), OR (File "umqtt/simple.py", line 57, in connect
IndexError: list index out of range), which I believe they are the same. Although when I tried to connect ESP32 to thingspeak (with some edits) it connected, sent and received data very well. So what is the problem?
My code:
import machine
import time
from machine import Pin, PWM
from umqtt.simple import MQTTClient
from time import sleep
import random
import json
import network
#################MQTT###################
def connect():
username="USER_NAME"
broker= "demo.thngsboard.io"
topic = "v1/devices/me/telemetry"
client = MQTTClient(username,broker)
try:
print("uuuuuuuuuu")
client.connect()
except OSError:
print('Connection failed')
sys.exit()
data = dict()
data["see"] = 15
data2=json.dumps(data)#convert it to json
print('connection finished')
client.publish(topic,data2)
print("kkkkkkkkkkkkkkkkkk")
time.sleep(5)
#print("Sending OFF")
connect()
Please note that I've seen that Question on micropython but it didn't fix my problem:
https://forum.micropython.org/viewtopic.php?t=4412
also I've seen that question in which he had A similar problem but he solved it without providing the solution:
Device not connecting to Thingsboard using MQTT
AND for sure I'm connecting it to the internet.

The problem seems to be, that umqtt from micropython only supports no authentication or user AND password authentication.
So I've edited my code as follows:
import machine
import time
from machine import Pin, PWM
from umqtt.simple import MQTTClient
from time import sleep
import random
import json
import network
#################MQTT###################
def connect():
username="Your_Token"
broker= "demo.thingsboard.io"
topic = "v1/devices/me/telemetry"
Mqtt_CLIENT_ID = "Client_ID" # Max. Number is 23 due to MQTT specs
PASSWORD=""
client = MQTTClient(client_id=Mqtt_CLIENT_ID, server=broker, port=1883, user=username, password=PASSWORD, keepalive=10000)
try:
client.connect()
except OSError:
print('Connection failed')
sys.exit()
data = dict()
data["see"] = 15
data2=json.dumps(data)#convert it to json
print('connection finished')
client.publish(topic,data2)
print("Data_Published")
time.sleep(5)
#print("Sending OFF")
connect()

Related

How to get rid of the error of keep_alive?

from keep_alive import keep_alive
with error
Import "keep_alive" could not be resolved
same directory, have the keep alive file
anyone help me?
basically how do do keep alive
from flask import Flask
from threading import Thread
app = Flask('')
app.route('/')
def main():
return "Bot is online."
def run():
app.run(host = "0.0.0.0", port = 8000)
def keep_alive():
server = Thread(target = run)
server.start()
This is what the keep_alive file contains, and name it like host.py or something. If you are naming it host.py then in your main.py you should add this too.
from host import keep_alive
keep_alive() #added at the bottom after all commands

Python Flask Socketio BadNamespaceError while sending data to server

I'm trying to send data to server from client but I get bad namespace error.
I searched for the error but didn't find any solution...
Can anyone point out what mistake I've done.
server side (app.py)
from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO
app = Flask(__name__)
socket_app = SocketIO(app)
#socket_app.on('userdata', namespace='/test')
def username(data):
print(data)
print(request.sid)
if __name__ == '__main__':
socket_app.run(app, debug=True, host='127.0.0.1', port=5000)
client side(client.py)
import socketio
sio = socketio.Client(engineio_logger=True)
data = {}
data['name'] = 'Mark'
sio.connect('http://127.0.0.1:5000')
sio.emit('userdata', data , namespace='/test')
sio.wait()
error
Attempting polling connection to http://127.0.0.1:5000/socket.io/?transport=polling&EIO=4
Polling connection accepted with {'sid': '1ipsM7udDVMj0WdKAAAA', 'upgrades': ['websocket'], 'pingTimeout': 5000, 'pingInterval': 25000}
Sending packet MESSAGE data 0
Attempting WebSocket upgrade to ws://127.0.0.1:5000/socket.io/?transport=websocket&EIO=4
WebSocket upgrade was successful
Traceback (most recent call last):
File "client.py", line 41, in <module>
sio.emit('userdata', data , namespace='/test')
File "/home/amit/anaconda3/envs/ANPR/lib/python3.6/site-packages/socketio/client.py", line 329, in emit
namespace + ' is not a connected namespace.')
socketio.exceptions.BadNamespaceError: /test is not a connected namespace.
Received packet NOOP data
flask & socketio versions
python-socketio==5.0.4 python-engineio==4.0.0 Flask==1.0.2
Flask-SocketIO==5.0.1
It looks like the OP figured out their own issue but when connecting to a non-default namespace you can specify it in the client connection:
sio.connect('http://127.0.0.1:5000', namespaces=['/test'])
I got this working by having the connect handler invoked in server.
#socket_app.on('connect', namespace='/test')
def test_connect():
print("connected")
emit('connect_custom', {'data': 'Connected'})
which then emits to client's connect_custom handler.
#sio.on('connect_custom', namespace='/test')
def on_connect(data):
print('client contacted by server')
print(data)
data = {}
data['name'] = 'Mark'
sio.emit('userdata', data, namespace='/test')
sio.connect('http://127.0.0.1:5000')

Autobahn websocket client in Quart (async Flask) application

Good evening everyone. I'm not quite new to this place but finally decided to register and ask for a help. I develop a web application using Quart framework (asynchronous Flask). And now as application became bigger and more complex I decided to separate different procedures to different server instances, this is mostly because I want to keep web server clean, more abstract and free of computational load.
So I plan to use one web server with a few (if needed) identical procedure servers. All servers are based on quart framework, for now just for simplicity of development. I decided to use Crossbar.io router and autobahn to connect all servers together.
And here the problem occurred.
I followed this posts:
Running several ApplicationSessions non-blockingly using autbahn.asyncio.wamp
How can I implement an interactive websocket client with autobahn asyncio?
How I can integrate crossbar client (python3,asyncio) with tkinter
How to send Autobahn/Twisted WAMP message from outside of protocol?
Seems like I tried all possible approaches to implement autobahn websocket client in my quart application. I don't know how to make it possible so both things are working, whether Quart app works but autobahn WS client does not, or vice versa.
Simplified my quart app looks like this:
from quart import Quart, request, current_app
from config import Config
# Autobahn
import asyncio
from autobahn import wamp
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
import concurrent.futures
class Component(ApplicationSession):
"""
An application component registering RPC endpoints using decorators.
"""
async def onJoin(self, details):
# register all methods on this object decorated with "#wamp.register"
# as a RPC endpoint
##
results = await self.register(self)
for res in results:
if isinstance(res, wamp.protocol.Registration):
# res is an Registration instance
print("Ok, registered procedure with registration ID {}".format(res.id))
else:
# res is an Failure instance
print("Failed to register procedure: {}".format(res))
#wamp.register(u'com.mathservice.add2')
def add2(self, x, y):
return x + y
def create_app(config_class=Config):
app = Quart(__name__)
app.config.from_object(config_class)
# Blueprint registration
from app.main import bp as main_bp
app.register_blueprint(main_bp)
print ("before autobahn start")
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
runner = ApplicationRunner('ws://127.0.0.1:8080 /ws', 'realm1')
future = executor.submit(runner.run(Component))
print ("after autobahn started")
return app
from app import models
In this case application stuck in runner loop and whole application does not work (can not serve requests), it becomes possible only if I interrupt the runners(autobahn) loop by Ctrl-C.
CMD after start:
(quart-app) user#car:~/quart-app$ hypercorn --debug --error-log - --access-log - -b 0.0.0.0:8001 tengine:app
Running on 0.0.0.0:8001 over http (CTRL + C to quit)
before autobahn start
Ok, registered procedure with registration ID 4605315769796303
after pressing ctrl-C:
...
^Cafter autobahn started
2019-03-29T01:06:52 <Server sockets=[<socket.socket fd=11, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 8001)>]> is serving
How to make it possible to work quart application with autobahn client together in non-blocking fashion? So autobahn opens and keeps websocket connection to Crossbar router and silently listen on background.
Well, after many sleepless nights I finally found a good approach to solve this conundrum.
Thanks to this post C-Python asyncio: running discord.py in a thread
So, I rewrote my code like this and was able to run my Quart app with autobahn client inside, and both are actively working in nonblocking fashion.
The whole __init__.py looks like:
from quart import Quart, request, current_app
from config import Config
def create_app(config_class=Config):
app = Quart(__name__)
app.config.from_object(config_class)
# Blueprint registration
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
# Autobahn
import asyncio
from autobahn import wamp
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
import threading
class Component(ApplicationSession):
"""
An application component registering RPC endpoints using decorators.
"""
async def onJoin(self, details):
# register all methods on this object decorated with "#wamp.register"
# as a RPC endpoint
##
results = await self.register(self)
for res in results:
if isinstance(res, wamp.protocol.Registration):
# res is an Registration instance
print("Ok, registered procedure with registration ID {}".format(res.id))
else:
# res is an Failure instance
print("Failed to register procedure: {}".format(res))
def onDisconnect(self):
print('Autobahn disconnected')
#wamp.register(u'com.mathservice.add2')
def add2(self, x, y):
return x + y
async def start():
runner = ApplicationRunner('ws://127.0.0.1:8080/ws', 'realm1')
await runner.run(Component) # use client.start instead of client.run
def run_it_forever(loop):
loop.run_forever()
asyncio.get_child_watcher() # I still don't know if I need this method. It works without it.
loop = asyncio.get_event_loop()
loop.create_task(start())
print('Starting thread for Autobahn...')
thread = threading.Thread(target=run_it_forever, args=(loop,))
thread.start()
print ("Thread for Autobahn has been started...")
from app import models
With this scenario we create task with autobahn's runner.run and attach it to the current loop and then run this loop forever in new thread.
I was quite satisfied with current solution.... but then then was found out that this solution has some drawbacks, that was crucial for me, for example: reconnect if connection dropped (i.e crossbar router becomes unavailable). With this approach if connection was failed to initialize or dropped after a while it will not try to reconnect. Additionally for me it wasn't obvious how to ApplicationSession API, i.e. to register/call RPC from the code in my quart app.
Luckily I spotted another new component API that autobahn used in their documentation:
https://autobahn.readthedocs.io/en/latest/wamp/programming.html#registering-procedures
https://github.com/crossbario/autobahn-python/blob/master/examples/asyncio/wamp/component/backend.py
It has auto reconnect feature and it's easy to register functions for RPC using decorators #component.register('com.something.do'), you just need to import component before.
So here is the final view of __init__.py solution:
from quart import Quart, request, current_app
from config import Config
def create_app(config_class=Config):
...
return app
from autobahn.asyncio.component import Component, run
from autobahn.wamp.types import RegisterOptions
import asyncio
import ssl
import threading
component = Component(
transports=[
{
"type": "websocket",
"url": u"ws://localhost:8080/ws",
"endpoint": {
"type": "tcp",
"host": "localhost",
"port": 8080,
},
"options": {
"open_handshake_timeout": 100,
}
},
],
realm=u"realm1",
)
#component.on_join
def join(session, details):
print("joined {}".format(details))
async def start():
await component.start() #used component.start() instead of run([component]) as it's async function
def run_it_forever(loop):
loop.run_forever()
loop = asyncio.get_event_loop()
#asyncio.get_child_watcher() # I still don't know if I need this method. It works without it.
asyncio.get_child_watcher().attach_loop(loop)
loop.create_task(start())
print('Starting thread for Autobahn...')
thread = threading.Thread(target=run_it_forever, args=(loop,))
thread.start()
print ("Thread for Autobahn has been started...")
from app import models
I hope it will help somebody. Cheers!

send data from celery to tornado websocket

I have some periodic tasks which I execute with Celery (parse pages).
Also I established a websocket with tornado.
I want to pass data from periodic tasks to tornado, then write this data to websocket and use this data on my html page.
How can I do this?
I tried to import module with tornado websocket from my module with celery tasks, but ofcourse, that didn't work.
I know only how to return some data, if I get a message from my client-side. Here is how I cope with it:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
'''
This is a simple Websocket Echo server that uses the Tornado websocket handler.
Please run `pip install tornado` with python of version 2.7.9 or greater to install tornado.
This program will echo back the reverse of whatever it recieves.
Messages are output to the terminal for debuggin purposes.
'''
class handler():
wss = []
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print ('new connection')
if self not in handler.wss:
handler.wss.append(self)
def on_message(self, message):
print ('message received: ' + message)
wssend('Ihaaaa')
def on_close(self):
print ('connection closed')
if self in handler.wss:
handler.wss.remove(self)
def check_origin(self, origin):
return True
def wssend(message):
print(handler.wss)
for ws in handler.wss:
if not ws.ws_connection.stream.socket:
print ("Web socket does not exist anymore!!!")
handler.wss.remove(ws)
else:
print('I am trying!')
ws.write_message(message)
print('tried')
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
myIP = socket.gethostbyname(socket.gethostname())
print ('*** Websocket Server Started at %s***' % myIP)
main_loop = tornado.ioloop.IOLoop.instance()
main_loop.start()
The option is to make a handle in tornado and then post results of celery task to this handle.
After that, there will be an opportunity to pass this data to websocket.

Python 3.x SimpleHTTPRequestHandler not outputting any response

Im trying to make a simple http server in python 3.x running on Windows 7 64-bit. I had this working fine on python 2.7 on my Mac, and made a few changes to upgrade to python 3.2 running on Windows.
When queried, the headers are all returned correctly, but there is no content showing in browser inspector - however telnet reveals that the response is being fully received!
Why does it not show up in the browser? HELP!
Code is:
import sys
import http.server
from http.server import HTTPServer
from http.server import SimpleHTTPRequestHandler
import usb.core
class MyHandler(SimpleHTTPRequestHandler):
def __init__(self,req,client_addr,server):
SimpleHTTPRequestHandler.__init__(self,req,client_addr,server)
def do_GET(self):
r="<h1>Hello World</h1>"
self.send_response(200)
self.send_header("Content-type", "application/json;charset=utf-8")
self.send_header("Content-length", len(r))
self.end_headers()
self.wfile.write(r.encode("utf-8"))
self.wfile.flush()
print(r)
HandlerClass = MyHandler
Protocol = "HTTP/1.1"
port = 80
server_address = ('localhost', port)
HandlerClass.protocol_version = Protocol
try:
httpd = HTTPServer(server_address, MyHandler)
print ("Server Started")
httpd.serve_forever()
except KeyboardInterrupt:
print('Shutting down server')
httpd.socket.close()
I fixed it - it needs "Access-Control-Allow-Origin" header adding:
self.send_header("Access-Control-Allow-Origin","*")
-- did the trick!

Resources