Python, serial readline, execute one time even if input is multiplied - python

I am writing a tool that reads serial /dev/ttyAMA0 (Ninja Pi Crust) from a Raspberry Pi and executes functions when a specific 433Mhz code is received.
So I got this door sensor that sends the code "010111010111011101010000" every time is triggered, I'm able to catch the event and trigger a function that sends me a pushover notification.
Door sensor is sending that signal 4-5 times to make sure the receiver catch the message so my loop executes a few times and here comes the problem, I don't want to receive 4/5 notification every time the door opens so I tried the counter +1 option which works fine but I don't know how to reset the counter after a specific amount of time since I want switch off notification for at least 5 minutes after triggering once.
I tried to flush serial buffer input after first reading, I've also tried to close / reopen serial connection but no luck as it will find again the same code and trigger my function again, any tips ?
import serial
from chump import Application
from time import sleep
serialport = serial.Serial(
port='/dev/ttyAMA0',
baudrate=9600,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS,
timeout=6
)
door = "010111010111011101010000"
def door_open():
message = user.create_message(
title='House Notification',
message="<b>Door Opened</b>",
html=True
)
message.send()
serialport.close()
sleep(5)
serialport.open()
while True:
command = serialport.readline()
print str(command) # just debugging
if door in command:
serialport.flushInput()
door_open()
sleep(10)
This is the code that I'm using, just removed pushover api vars.

Changing the source to:
def door_open():
message = user.create_message(
title='House Notification',
message="<b>Door Opened</b>",
html=True
)
message.send()
serialport.flushInput()
while True:
command = serialport.readline()
print str(command)
if door in command:
sleep(10)
door_open()
Now even if the code is sent 5 times from the transmitter it will only get one and trigger the function.
This answer was posted as an edit to the question Python, serial readline, execute one time even if input is multiplied by the OP deepred under CC BY-SA 3.0.

Related

Python Serial Writing but seemingly not reading. Raspberry Pi 0 to Arduino

I'm having trouble with a python script running on an RPI0 reading serial input from an Arduino. I know the Arduino's code is correct as everything works as intended interacting with the Arduino over the built in serial monitor in the Arduino software(send code a10(code to drive a relay HIGH), Arduino sends back 11(basically asking for how long), send code b5, Arduino will hold pin HIGH for 5 seconds(b5)).
However when I attempt to read any serial input in python using the pyserial module, nothing happens. I know it does successfully send the code to the arduino as it will hold the pin HIGH for the specified seconds when I rewrite the python script with ser.write("a10b5").
The serial connection is NOT USB. I'm using jumper wires with a voltage shifter in between them using the Arduino's and Pi's GPIO TX and RX pins.
using python -V in the terminal it tells me I'm running version 3.8
I've tried multiple baud rates(300, 1200, 9600, 57600) with no change in behavior
I've also tried changing if x == 11: to if x == "11": in case for some reason it was receiving strings and not ints, also to no avail.
Here is the code:
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=None
)
print("sending data over serial now")
ser.write("a10") #a10 is relay HIGH code
while True:
x = ser.read()
if x == 11: ##arduino code 11(asking for how long)
print("recieved code 11")
print("arduino recieved relay HIGH code and is waiting for time to hold relay for")
print("sending time now")
ser.write('a5') # 5 seconds
time.sleep(1)
if x == 13: #arduino code 13(water success)
print("recieved code 13")
print("arduino reports watering complete")
x = 0 ##this is to clear the variable every loop. Not sure if it's needed
And here is a simple serial reader I've pulled from online. Opening it up in a second terminal and running it at the same time with my own script it will actually read the codes from the arduino business as usual.
#!/usr/bin/env python
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while True:
x=ser.readline()
print x
What gives?
Answering my own question. In the arduino code I used
Serial.println(whatevergoeshere)
instead of
Serial.print(whatevergoeshere)
So the arduino was sending out '\n' at the end of every serial line that was not being printed by either the arduino serial console and the python script. Updating my IF statements in python to
if x == "11\n":
Solves the issue and everything works as intended.

Using Python to Automate SMS reply using Raspberry pi w/ Quectel EC25

I made a 4g hotspot last year with a Quectel ec25 and raspberry pi, it has worked just fine for this purpose. Earlier this year I wanted to expand its capabilities to automatically reply to text messages with status updates for certain systems. I was able to figure out sending and receiving a text message with AT commands just fine but I am having trouble getting python to recognize and respond to a text message with key words. I found this code,
http://www.python-exemplary.com/index_en.php?inhalt_links=navigation_en.inc.php&inhalt_mitte=raspi/en/gsm.inc.php, and have modified it slightly to make the EC25 work with the USB serial.
I have 2 SSH sessions going at once, one with the command line up and the other with a minicom session to monitor serial. the EC25 is sending indications to the Pi that it is receiving a message, its output when a message is received is "+CMTI: "ME",0" but the pi has no response to it. The code seems to be unresponsive on this part. it will print "listening for incoming SMS..." but then it will never go beyond that, even when it receives text messages.
reply = ser.read(ser.inWaiting())# Clean buf
print "Listening for incoming SMS..."
while True:
reply = ser.read(ser.inWaiting())
if reply != "":
I have tried it with just ser.read() and ser.inWaiting() but that sends it into a bad feedback loop.
Here is my code.
# SIMSMS1.py
# pip install pyserial
import RPi.GPIO as GPIO
import serial
import time, sys
import datetime
P_BUTTON = 24 # Button, adapt to your wiring
def setup():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(P_BUTTON, GPIO.IN, GPIO.PUD_UP)
SERIAL_PORT = "/dev/ttyUSB3" # Raspberry Pi 3
ser = serial.Serial(SERIAL_PORT, baudrate = 115200, timeout = 5)
setup()
ser.write("AT+CMGF=1\r") # set to text mode
time.sleep(1)
ser.write('AT+QURCCFG="urcport","usbmodem"\r') #set URC Indication
time.sleep(1)
ser.write('AT+CPMS="ME","ME","ME"\r') #set memory to Mobile equipment message storage
time.sleep(1)
ser.write('AT+CMGD=1,4\r') # delete all SMS
time.sleep(1)
reply = ser.read(ser.inWaiting())# Clean buf
print "Listening for incoming SMS..."
while True:
reply = ser.read(ser.inWaiting())
if reply != "":
ser.write("AT+CMGR=1\r") # read message
time.sleep(3)
reply = [ser.read(ser.inWaiting())]
print "SMS received. Content:"
print reply
if "getStatus" in reply:
t = str(datetime.datetime.now())
if GPIO.input(P_BUTTON) == GPIO.HIGH:
state = "Button released"
else:
state = "Button pressed"
ser.write('AT+CMGS="+1xxxxxxxxxx"\r') #designate phone number
time.sleep(3)
msg = "Sending status at " + t + ":--" + state
print "Sending SMS with status info:" + msg
ser.write(msg + chr(26))
time.sleep(3)
ser.write('AT+CMGD=1,4\r') # delete all messages
time.sleep(3)
ser.read(ser.inWaiting()) # Clear buf
time.sleep(5)
this is the output of on the serial, the last line is a message being received
AT+CMGF=1
OK
AT+QURCCFG="urcport","usbmodem"
OK
AT+CPMS="ME","ME","ME"
+CPMS: 0,255,0,255,0,255
OK
AT+CMGD=1,4
OK
+CMTI: "ME",0
I know it has something to do with the "reply = ser.read(ser.inWaiting())" but i cant figure out what to write to make it work. Thank you in advance
The easiest way might be polling the message received.
Maybe the EC25 has some possible gpio. Once any message comes, the gpio would generate a pulse signal.

How do I add timeout, in order to move to next client if current client has not sent any data?

How do I add timeout, in order to move to next client if current client has not sent any data in Python? I have my all the connected clients stored in the conn_clients list.
Here's my code for receive function:
def receive(connection):
curr_con = connection
while True:
message = connection.recv(BUFFER_SIZE)
if not message:
print "Closing connection"
conn_clients.remove(connection) #removing socket from list
return
send_all(curr_con, message) #sending message to all cleints
You did not mention the operating system, and I'm not sure if this is applicable for Windows.
GLib provides timeout functions which you can start and tell to execute a function after a certain interval. I found this article which shows how to connect g_io_add_watch to socket events (much cleaner that waiting for events) and simultaneously start a timer (from the same library). If the socket doesn't show activity in the time set, the function can abort the socket process.

How do i debug this USB-Serial connection?

I am trying to talk to a Stanford Research Systems SR760 spectrum analyzer on my mac (10.7.5) via Serial, using a Serial-to-USB adapter to connect to my laptop. I am using the Prolific USB-serial driver. Not sure which but I installed it recently. It probably is the PL2303 one.
Using Python, here's some sample code
import time
import serial
# configure the serial connections (the parameters differs on the device you
# are connecting to)
ser = serial.Serial(
port='/dev/cu.PL2303-0000201A',
baudrate=19200,
parity=serial.PARITY_NONE,
bytesize=serial.EIGHTBITS,
stopbits=serial.STOPBITS_ONE,
rtscts=0,
dsrdtr=0,
timeout=2,
)
if ser.isOpen():
ser.flushInput()
ser.flushOutput()
print """Enter your commands below.\r\nInsert "exit" to leave the
application."""
while 1:
# get keyboard input
input = raw_input(">> ")
if input == 'exit':
ser.close()
exit()
else:
ser.write(input + '\r')
out = ''
# let's wait one second before reading output (let's give device
# time to answer)
lines = 0
while 1:
time.sleep(1)
out = out + ser.readline()
lines = lines + 1
if lines > 5:
break
print "read data: " + out
Using the SR760's manual, I send it: *IDN?, a basic "identify" command. I expect for something to pop up in my terminal, nothing does. It just times out. However, if I look at the send queue on the SR760, it will show the identity string, and in fact responds to a bunch of different commands. I'm just not getting anything on my computer and that is the problem. I know it is supposed to work that way because my colleague wrote code that words on his computer (a windows laptop).
How do I even start debugging this? I've tweaked the timeout, and confirmed the sr760 had the same parameters I was expecting.

PySerial - Full-duplex communication

Is it possible to achieve full-duplex communication using PySerial? Specifically, would it be possible to monitor the port continuously for input and write whenever needed? I imagine it should be possible using threads (and serial interfaces are full duplex no?). If not, what would be the best approach to monitoring a serial port when not transmitting? A timeout?
Edit: Here's my attempt at it. This code is targeting TI's CC2540 Bluetooth LE chip. On sending the GATT init message I expect a reply (detailing the operating parameters of the chip)...I'm getting nothing though
import serial
import threading
from time import sleep
serial_port = serial.Serial()
GAP_DeviceInit = \
"\x01\x00\xfe\x26\x08\x03\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
def read():
while True:
data = serial_port.read(9999);
if len(data) > 0:
print 'Got:', data
sleep(0.5)
print 'not blocked'
def main():
serial_port.baudrate = 57600
serial_port.port = '/dev/ttyACM0'
serial_port.timeout = 0
if serial_port.isOpen(): serial_port.close()
serial_port.open()
t1 = threading.Thread(target=read, args=())
while True:
try:
command = raw_input('Enter a command to send to the Keyfob: \n\t')
if (command == "1"):
serial_port.write(message)
except KeyboardInterrupt:
break
serial_port.close()
Yes serial port hardware is full duplex. Yes, you can use threads to do Rx and Tx at the same time. Alternatively, you can use a single thread loop that does reads with a short timeout and alternates between reading and writing.
You didn't specify a timeout, so the read waits for the full number of bytes to receive and only then displays anything.

Categories