Reliably write and read to serial using python - python-2.7

I am communicating with a Fona 808 module from a Raspberry Pi and I can issue AT commands, yey!
Now I want to make a python program where I can reliably issue AT commands using shortcut commands like "b" for getting the battery level and so on.
This is what I have so far:
import serial
con = serial.Serial('/dev/ttyAMA0',timeout=0.2,baudraute=115200)
def sendAtCommand(command):
if command == 'b':
con.write("at+cbc\n".encode())
reply = ''
while con.inWaiting():
reply = reply + con.read(1)
return reply
while True:
x = raw_input("At command: ")
if x.strip() == 'q':
break
reply = sendAtCommand(x)
print(reply)
con.close()
In the sendAtCommand I will have a bunch of if statements that send different at commands depending on the input it receives.
This is somewhat working but is very unreliable. Sometimes I get the full message. Other times I get nothing. Then double message next time and so on.
I would like to create one method that issues a command to the Fona module and then reads the full response and returns it.
Any suggestions?

Your loop quits if the 'modem' has not responded anything to your at command yet. You should keep reading the serial input until you get a linefeed or until a certain time has passes e.g. 1 second or so.

Okay. It turns out this is pretty trivial.
Since at commands always return OK after a successful query then it is simply a matter of reading the lines until eventually one of them will contain 'OK\r\n'.
Like so:
def readUntilOK():
reply=''
while True:
x = con.readline()
reply += x
if x == 'OK\r\n':
return reply
This does not have a timeout and it does not check for anything else than an OK response. Which makes it very limiting. Adding error handling is up to the reader. Something like if x == 'ERROR\r\n' would be a good start.
Cheers!

Related

Custom C++ App returns "Syntax Error" when sending specific AT Commands

I'm trying to write a C++ app, that is able to make some phone calls. For this, I ordered a USB GSM Module, and a SIM Card with a prepaid contract.
I tested the module in PuTTY and everything works as expected. I choose a COM Port and can send/receive messages. See example:
AT
OK
AT+CMEE=2
OK
But when I try sending these commands via my own application, SOME of them fail (e.g. AT+CMEE=2).
AT
OK
AT+CMEE=2
+CMEE ERROR: Syntax Error
Other commands, such as unlocking the SIM Card work fine as well. But e.g "ATD" doesn't work. Here is the code for writing to the serial port. Keep in mind this is just for testing purposes:
DWORD dummy;
// "buffer" is just an std::string
char* string = new char[buffer.length() + 3]; // "+3" because I append '\0' later when printing
strcpy(string, buffer.c_str());
string[buffer.length()] = ' ';
string[buffer.length() + 1] = '\r';
WriteFile(m_hCom,
string,
(buffer.length() + 2) * sizeof(char),
&dummy,
0
);
I tried several variations ('\0' at the end, no space in between, etc) but all of those led to no commands working at all. So this is the solution where at least some commands are working and responding.
Any more ideas what could be wrong here?
It depends on the operating mode, but sometimes you should terminate the AT command with a \r\n when working with GSM modems. See this post. It looks like you are only adding a \r

DECRBY in Redis not working in Python code

I am using redis in my Python code to store keys, however there the Python code wasn't running as it was supposed to. I haven't found any errors in my code, so I started turning things into comments and I found that the redis command DECRBY doesn't seem to work.
I have tried all the various commands such as INCR, INCRBY, and DECR and those work. But DECRBY isn't acting as expected (even though it is the same syntax as INCRBY and that works).
elif (text == "test1"):
r.incr(count)
send_message(sender_id, r.get(count))
elif (text == "test2"):
r.incrby(count,10)
send_message(sender_id, r.get(count))
elif (text == "test3"):
r.decr(count)
send_message(sender_id, r.get(count))
elif (text == "test4"):
r.decrby(count,10)
send_message(sender_id, r.get(count))
My program sends a message through Facebook regarding the result. I have the code in a try statement and an exception that sends a message that says "Exception".
I have initialized the count to 8, and as you can see here:
https://imgur.com/a/bSipS3Q .
It throws the exception for test4 which is DECRBY.
I have tried the commands in the Redis CLI, and DECRBY works in the command line, but not when from the python program.
The workaround I am using right now is the INCRBY method by the negative of the value I want to decrease.
Is there a reason why the DECRBY wouldn't work? I can't figure out why r.incrby works, but changing it to r.decrby leaving everything else constant doesn't. Is there a way to debug this?

subprocess.popen stream handling

Is it possible to prevent subprocess.popen from showing prompts in the terminal?
Attempting to map a drive but would like to read the prompt for credentials in the script rather than display them to the terminal. The idea being I can carry out actions based on the response.
I am aware the use of shell is frowned upon when using string based commands (for obvious reasons), however I'm controlling the input so am happy with the risk for testing purposes.
I was under the impression that all stdout (interaction) would be parsed into the output_null variable. Instead I am still getting the prompt in the terminal (as illustrated below). I'm either miss understanding how the streams work or I'm missing something. Can anyone enlighten me please
command = "mount -t smbfs //{s}/SYSVOL {m}".format(s=server, m=temp_dir)
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output_null = p.communicate()[0]
if "Password for" in output_null:
print 'awdaa'
Terminal Shows
Password for 192.168.1.111:

Test a program that uses tty stdin and stdout

I have a software made of two halves: one is python running on a first pc, the other is cpp running on a second one.
They communicate through the serial port (tty).
I would like to test the python side on my pc, feeding it with the proper data and see if it behaves as expected.
I started using subprocess but then came the problem: which stdin and stdout should I supply?
cStringIO does not work because there is no fileno()
PIPE doesn't work either because select.select() says there is something to read even if nothing it's actually sent
Do you have any hints? Is there a fake tty module I can use?
Ideally you should mock that out and just test the behavior, without relying too much on terminal IO. You can use mock.patch for that. Say you want to test t_read:
#mock.patch.object(stdin, 'fileno')
#mock.patch.object(stdin, 'read')
def test_your_behavior(self, mock_read, mock_fileno):
# this should make select.select return what you expect it to return
mock_fileno.return_value = 'your expected value'
# rest of the test goes here...
If you can post at least part of the code you're trying to test, I can maybe give you a better example.

Condor output file updating

I'm running several simulations using Condor and have coded the program so that it outputs a progress status in the console. This is done at the end of a loop where it simply prints the current time (this can also be percentage or elapsed time). The code looks something like this:
printf("START");
while (programNeedsToRum) {
// Run code repetitive code...
// Print program status update
printf("[%i:%i:%i]\r\n", hours, minutes, seconds);
}
printf("FINISH");
When executing normally (i.e. in the terminal/cmd/bash) this works fine, but the condor nodes don't seem to printf() the status. Only once the simulation has finished, all the status updates have been outputted to the file but then it's no longer of use. My *.sub file that I submit to condor looks like this:
universe = vanilla
executable = program
output = out/out-$(Process)
error = out/err-$(Process)
queue 100
When submitted the program executes (this is confirmed in condor_q) and the output files contain this:
START
Only once the program has finished running its corresponding output file shows (example):
START
[0:3:4]
[0:8:13]
[0:12:57]
[0:18:44]
FINISH
Whilst the program executes, the output file only contains the START text. So I came to the conclusion that the file is not updated if the node executing program is busy. So my question is, is there a way of updating the output files manually or gather any information on the program's progress in a better way?
Thanks already
Max
What you want to do is use the streaming output options. See the stream_error and stream_output options you can pass to condor_submit as outlined here: http://research.cs.wisc.edu/htcondor/manual/current/condor_submit.html
By default, HTCondor stores stdout and stderr locally on the execute node and transfers them back to the submit node on job completion. Setting stream_output to TRUE will ask HTCondor to instead stream the output as it occurs back to the submit node. You can then inspect it as it happens.
Here's something I used a few years ago to solve this problem. It uses condor_chirp which is used to transfer files from the execute host to the submitter. I have a python script that executes the program I really want to run, and redirects its output to a file. Then, periodically, I send the output file back to the submit host.
Here's the Python wrapper, stream.py:
#!/usr/bin/python
import os,sys,time
os.environ['PATH'] += ':/bin:/usr/bin:/cygdrive/c/condor/bin'
# make sure the file exists
open(sys.argv[1], 'w').close()
pid = os.fork()
if pid == 0:
os.system('%s >%s' % (' '.join (sys.argv[2:]), sys.argv[1]))
else:
while True:
time.sleep(10)
os.system('condor_chirp put %s %s' % (sys.argv[1], sys.argv[1]))
try:
os.wait4(pid, os.WNOHANG)
except OSError:
break
And my submit script. The problem ran sh hello.sh, and redirected the output to myout.txt:
universe = vanilla
executable = C:\cygwin\bin\python.exe
requirements = Arch=="INTEL" && OpSys=="WINNT60" && HAS_CYGWIN==TRUE
should_transfer_files = YES
transfer_input_files = stream.py,hello.sh
arguments = stream.py myout.txt sh hello.sh
transfer_executable = false
It does send the output in its entirety, so take that in to account if you have a lot of jobs running at once. Currently, its sending the output every 10 seconds .. you may want to adjust that.
with condor_tail you can view the output of a running process.
to see stdout just add the job-ID (and -f if you want to follow the output and see the updates immediately. Example:
condor_tail 314.0 -f