I’m using cu and pexpect to do basically the same thing. The nice thing about pexpect is it gives you a good framework to parse out the results of AT commands and also to deal with errors in a reasonable way.
Right now it is all contained in a huge wrapper class that abstracts various AT commands and returns their results.
This thread gives some example code I used using this technique.