How do I publish a stream of varying data to a MQTT broker, using micropython - mqtt

I'm trying to create a basic weather station using a Raspberry Pi Pico W. I'm using a pimoroni pico explorer board and a BME280 breakout. I have been able to get the pico to publish to a topic and it will send a message when a single button is pressed, but I'm struggling to get it to publish temperature and humidity values rather than just a message.
I think I've worked out where the problem lies, but I don't know enough about micropython to be able to work out how to fix this issue.
I started with this code, to get the message button pressed when I pressed a button connected to the pico.
mqtt_server = 'broker.mqttdashboard.com'
client_id = 'bigles'
topic_pub = b'cherub'
topic_msg = b'Button Pressed'
Then I changed the topic message to be bme280.read as I figured that would give me 3 values and then I can go from there.
My initial thought process was that because the topic_msg is publishing a statment surrounded by '', it's just going to publish exactly whats between those quotes, right? So lets just remove the brackets and have:
topic_msg = bme280.read()
because it need to publish those values. Then I got the error code
Traceback (most recent call last):
File "<stdin>", line 17
SyntaxError: invalid syntax
So I tried topic_msg = (bme280.read()), but got invalid syntax again
Than I tried
temp = bme280.read()
topic_msg = 'temp'
Resulting in the message "temp" appearing in my broker.
I've tried defining temp as a function, only to be told that it has no len(). I tried addign len, using example code from the internet. It didnt work. I am out of ideas, can anyone suggest anything? Any resources, solutions, suggested google gterms ect, like I said, I'm really new to this. Thanks
Full code with my current edits:
import time
from breakout_bme280 import BreakoutBME280
from pimoroni_i2c import PimoroniI2C
from pimoroni import PICO_EXPLORER_I2C_PINS
i2c = PimoroniI2C(**PICO_EXPLORER_I2C_PINS)
bme = BreakoutBME280(i2c, address=0x76)
import network
import time
from umqtt.simple import MQTTClient
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("i can hear what u sayin","12345678")
time.sleep(5)
print(wlan.isconnected())
def temp
temp = bme.read()
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_pub = b'Temp'
topic_msg =
def mqtt_connect():
client = MQTTClient(client_id, mqtt_server, keepalive=3600)
client.connect()
print('Connected to %s MQTT Broker'%(mqtt_server))
return client
def reconnect():
print('Failed to connect to the MQTT Broker. Reconnecting...')
time.sleep(5)
machine.reset()
try:
client = mqtt_connect()
except OSError as e:
reconnect()
while True:
if bme.read():
client.publish(topic_pub, topic_msg)
time.sleep(5)
else:
pass

# Following lines are incorrect- incorrect syntax
# def temp
# temp = bme.read()
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_pub = b'Temp'
topic_msg = str(bme.read()) # convert received value into string
Also, in your while loop, you publish the same previously recorded value topic_msg and never read into it again.
Also, move out sleep time.sleep(5) outside if, into loop
Also, suggestion to fix wifi part:
wlan.connect('wifi', 'pass')
while not wlan.isconnected():
pass
print("Connected:", wlan.ifconfig())

Related

Capture ANSI escape sequence response using Micropython ESP8266

I'm using an ESP8266 with Micropython to communicate with a serial terminal using Putty. Using escape sequences like referenced in these questions:
Read ANSI escape from terminal
How do I determine size of ANSI terminal?
List of escape sequences https://vt100.net/docs/vt100-ug/chapter3.html
I am trying to read back an escape sequence that is a reply to find the cursor position.
I can see the response in the terminal, but I need to capture it so I can parse it. I'm familiar with Python, but a complete noob with Micropython and the ESP8266 (ESP01). I'm using the webrepl to upload the code. I saw this and I'm not sure if it's related: https://forum.micropython.org/viewtopic.php?t=5359
I've tried running my code without webrepl connected, but it still didn't work.
What am I doing wrong, how can I capture the response?
Depending on the terminal size, the response should be something like below, the stuff before the ; will not be visible.
^[[45;157R
#import esp
import network
import machine
from machine import UART
uart = UART(0, 115200)
x=uart.write("\033[500;500H\033[6n")
if uart.any():
print(":> ", uart.read())
EDIT: Tried example from this link https://forum.micropython.org/viewtopic.php?t=5359#p30867
No luck with that either (yes, I know it's blocking). Here if I type the letter 'R', it drops out of the loop, but it's not catching the output from the escape sequence.
from machine import UART
import machine
import network
import uos
uos.dupterm(None, 1)
uart = UART(0, 115200)
charbuf = None
uart.write("\033[500;500H\033[6n")
while charbuf != b"R":
if uart.any():
charbuf = uart.read()
uart.write(charbuf)
uos.dupterm(UART(0, 115200), 1)
Solving this was a nightmare, the WebRepl console replication has been the bane of my existence and probably many others. I tried multiple read() methods and they all failed.
uart.read()
sys.stdin.read()
sys.stdin.buffer.read()
Those were in combination of enabling/disabling the console duplication for webrepl.
The incantation that finally worked for me is below. See inline comments for more details.
import machine
import network
#import sys
import uos
from machine import UART
uos.dupterm(None, 1) # Disable console duplication for Webrepl
uart = UART(0, 115200, timeout=100, timeout_char=100) #Instantiate uart, increase timeout for good measure
uart.write("\033[2J\033[1;1f") # Clear screen
uart.write("\033[500;500H\033[6n") # Move cursor to bottom right, send query.
# Wait for uart to collect response. This will block further execution until we get a reply.
while True:
if uart.any() != 0:
break
uos.dupterm(UART(0, 115200), 1) # Re-enable console redirection so print() will work
# Read the uart buffer with response, convert from binary to string, replace ESC character.
# First ^ gets eaten somewhere!
buf = str(uart.read(), 'UTF-8').replace('\x1b', '^^[')
if len(buf) > 0: # If response isn't empty, print buffer
print(buf)
This is the Output:
^[[43;157R

How to deal with "OSError: Available Interfaces are down" error message?

I am currently working with a Pycom device and try to connect it to an IoT platform (more precisely, Adafruit IO). I would like to make the platform and my device communicate. It used to work perfectly good, I could publish and subscribe using MQTT to topics/widgets configured on the website but lately, I have been given this error message when trying to connect to Adafruit with this protocol : OSError: Available Interfaces are down. I do not know why all of a sudden, this happens and I have no idea how to deal with. Sometimes, after a while or after numerous attempts, it works again but I would like to know more precisely what this is due to.
import umqtt
from umqtt import MQTTClient
import ubinascii
import micropython
import time
import machine
import pycom
pycom.heartbeat(False)
IO_SERVER = "io.adafruit.com"
AIO_SERVER = "io.adafruit.com"
AIO_PORT = 1883
AIO_USER = "user"
AIO_KEY = "key"
AIO_CLIENT_ID = ubinascii.hexlify(machine.unique_id()) # Can be anything
client = MQTTClient(AIO_CLIENT_ID, AIO_SERVER, AIO_PORT, AIO_USER, AIO_KEY)
import network
from network import WLAN
wlan=WLAN(mode=WLAN.STA)
pw='pw'
nets=wlan.scan()
for net in nets:
if net.ssid == 'myssid':
wlan.connect(net.ssid,auth=(None,pw),timeout=5000)
if wlan.isconnected() == True:
pycom.rgbled(0x007f00)
else:
pycom.rgbled(0x7f0000)
client.connect()
pycom.rgbled(0x7f7f00)
I used the umqtt module located here: https://github.com/micropython/micropython-lib/blob/master/umqtt.simple/umqtt/simple.py. I can connect to my wifi with no problem, the error happens at client.connect().
I had faced similar issue, what I realised is that there is some time required for the client to connect.
Add 2 sec delay before connect & like 10 secs

Get application data in net frame via tshark command line

Here I need parse a custom protocol in many .pcapng files , I want direct filter and output the application raw data via tshark command .
At first , I use the "-e data.data" option , but ,some of the application data could be decode as other protocol , and wouldn't be output by -e data.data.
Then , I find a way that special the "disable-protocol" file under wireshark profile folder,but ,I must take the profile file and deploy it before run the parse program on other PC.
And, I tried disable all the protocol except udp and tcp ,but it can't work.
I also disable the known conflict protocols , it works ,but there may be same mistake on other unknown protocol and the tshark's output still can't be trust completely.
I works on Windows7 and wireshark 2.2.use python 2.7 for parse work.
In a summary , what I want is a portable command line that can flexible and direct output all data after UDP information in a net frame.
could I disable decode on some ports by just add options in command line?
EDIT1:
I find in wireshark 1.12,there is a "Do not decode" option in "decode as..." dialog , if enable it,the display is what I want.but in wireshark 2.2,they removed the option.and I still need a command line to do this filter.
After 48 hours and 26 times viewed ,it still no response but one vote up.
I already give up this way, and decode the frame by myself.
what I want is the udp srcport and dstport, and the application data.
In actual , every net frame has a same length of header , so ,it's easy to strip the header by a fixed offset , and get the special data.
In my case , I just do some filter and use -x option for output.,as this:
tshark -r xxx.pcapng -j udp -x
the output may looks like this:
(just for example,not real case)
Every line contains three parts :The first column is offset reference, the next 16 columns are bytes in hex , and the remains are the characters map to the data.
My code:
def load_tshark_data(tshark_file_path):
tshark_exe = "c:/Program Files/Wireshark/tshark.exe"
output = subprocess.check_output([
tshark_exe,
"-r",tshark_file_path,
"-j","udp",
"-x"
])
hex_buff = ""
line_buff = ""
for c in output:
if c == "\n":
if len(line_buff) > 54:
hex_buff += line_buff[5:53]
line_buff = ''
else:
src_port = int(hex_buff[0x22*3 : 0x24*3].replace(" ",""),16)
dst_port = int(hex_buff[0x24*3 : 0x26*3].replace(" ",""),16)
app_data = hex_buff[0x2a*3 : ].strip(" ")
hex_buff = ""
yield [src_port, dst_port, app_data]
else:
line_buff += c
hope this can help any one also blocked by such a problem

trying to read from stdout with NONBLOCKING set using winARM newlib lpc

I want read on stdout to be non-blocking. I was using the newlib-lpc library in WINarm to do this. But even though it is set as non-Blocking, the code stops at read every time and waits for a character to be received.
Here is my read line:
read(fileno(stdout), &inchar, 1);
Here is the code to set stdout to non-blocking using newlib-lpc
blocking=BLOCKING_IO_NO;
ioctl( fileno(stdout), BLOCKING_SETUP, &blocking);
When that didn't work, I decided to forget using the library and do it myself with this line
fcntl(fileno(stdout), F_SETFL,fcntl(fileno(stdout), F_GETFL) |O_NONBLOCK);
But that didn't work either.
Could anyone give me some advice?
Thanks!
edit:
Someone asked if I really meant stdout. Yes, I am resurrecting some old code, and the stdout has been set as the socket for UART communication between my board and the computer.
sp.baud = 115200uL;
sp.length = UART_WORD_LEN_8;
sp.parity = UART_PARITY_NONE;
sp.stop = UART_STOP_BITS_1;
ioctl( fileno(stdout), UART_SETUP, &sp);
irq.FIQ = 0;
irq.pri = (INT_PRIORITY)10;
ioctl( fileno(stdout), INTERRUPT_SETUP, &irq);
edit2: They used stdout this way so that printf works. When it tries to print to stdout, it gets redirected to the UART serial stream.
edit3: The error I get when calling
ioctl( fileno(stdout), BLOCKING_SETUP, &blocking);
is
errno88 function not implemented

Apple Push Notifications (APN) service server side Python 2 script in iOS

I have configured my iOS application with Apple Push Notification (APN) service enabled. I was able to send notifications to devices with PHP and Python 3 scripts. I tested both on local server with local machine. But now I need to write the script in Python2.
Below is the script I've written and when I run this I get nothing. Neither a notification to my device nor error in command line.
import socket, ssl, json, struct
import binascii
import os
deviceToken = 'my_device_tocken_without_spaces'
thePayLoad = {
'aps': {
'alert':'My first push notification!',
'sound':'default'
}
}
theCertfile = 'ck3_2.pem'
theHost = ( 'gateway.sandbox.push.apple.com', 2195 )
data = json.dumps( thePayLoad )
theFormat = '!BH32sH%ds' % len(data)
theNotification = struct.pack( theFormat, 0, 32, deviceToken, len(data), data )
ssl_sock = ssl.wrap_socket( socket.socket( socket.AF_INET, socket.SOCK_STREAM ), certfile = theCertfile )
ssl_sock.connect( theHost )
ssl_sock.write( theNotification )
ssl_sock.close()
What did I miss? How can I check where is the mistake happen?
I ran PHP script in localhost using XAMPP and I ran Python script in command line because I was unable to set-up Python with XAMPP which I already posted a question here.
you may consider https://github.com/djacobs/PyAPNs that wrapped lot of useful features, including:
error handling
support enhanced message format and auto resend messages which are sent before error response
non-blocking ssl socket connection with great performance
I think there's nothing wrong with your code. You can try adding following lines after ssl_sock.connect( theHost )
print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())
Which will print information about ssl of your connection.
Alternatively you can create a sample server and change the connections in your client and test against the server. http://carlo-hamalainen.net/blog/2013/1/24/python-ssl-socket-echo-test-with-self-signed-certificate
You imported binascii, but you forgot to use it.
Convert the token and json data to byte arrays, e.g.:
deviceToken = binascii.a2b_hex('my_device_tocken_without_spaces')
and
data = json.dumps(thePayLoad, separators=(',', ':'), ensure_ascii=False).encode('utf-8')

Resources