Giter Site home page Giter Site logo

veeso / attila Goto Github PK

View Code? Open in Web Editor NEW
24.0 2.0 10.0 209 KB

Python module to communicate easily with modems and RF modules using AT commands

License: MIT License

Python 100.00%
at-command modem rf rf-module serial-communication serial-port serialport python python3 python37

attila's Introduction

ATtila

Changelog Β· Get started Β· Documentation

~ Communicate easily with modems and RF modules using AT commands ~

Developed by @veeso

Current version: 1.2.3 (23/09/2022)

License-MIT Repo stars latest version download counters Ko-fi

Build CI Coveragg



pip3 install attila

About ATtila πŸ“’

ATtila is both a Python3 🐍 module and a CLI utility. The module's purpose is to ease the communication with devices through serial port, automating the scripts execution workflow; in particular ATtila is designed for RF modules which use AT commands.

It is both possible to send single AT commands indicating what is the expected response, what information to store for each command and define an alternative behaviour in case of an unexpected responses.
These are the main functionalities that ATtila provides:

  • FaΓ§ade to communicate with the serial devices
  • Sending AT commands and define the expected response for it
  • Collect values from response and store them in the session storage
  • Define a command to execute in case the previously executed command fails
  • Sending individual AT command to RF module/modem through serial port and get the response

ATtila comes, as said before, with a binary (which can be used instead of the classic chat binary) to pair with pppd, or for anything you want. You can run ATtila binary with

python3 -m attila
#Or if installed, just
attila
Usage: attila [OPTION]... [FILE]

  With no FILE, run in interactive mode

  -p  <device path>     Use this device to communicate
  -b  <baud rate>       Use the specified baudrate to communicate
  -T  <default timeout> Use the specified timeout as default to communicate
  -B  <break>           Use the specified line break [CRLF, LF, CR, NONE] (Default: CRLF)
  -A  <True/False>      Abort on failure (Default: True)
  -L  <logfile>         Enable log and log to the specified log file (stdout is supported)
  -l  <loglevel>        Specify the log level (0: CRITICAL, 1: ERROR, 2: WARN, 3: INFO, 4: DEBUG) (Default: INFO)
  -v                    Be more verbose
  -q                    Be quiet (print only PRINT ESKs and ERRORS)
  -h                    Show this page

Requirements πŸ›’

  • Python3.5 (>= 1.2.0)
    • Python3.4 (up to 1.1.x - switch to 1.1.x branch)
  • pyserial3

Get Started πŸ› 

In order to build your own implementation using ATtila these are the steps you need to follow:

  1. Import the AT Runtime Environment into your project

    The first thing you have to do is to import the AT Runtime Environment and the exceptions it can raise in your project

    from attila.atre import ATRuntimeEnvironment
    from attila.exceptions import ATREUninitializedError, ATRuntimeError, ATScriptNotFound, ATScriptSyntaxError, ATSerialPortError
  2. Instantiate an ATRuntimeEnvironment object

    atrunenv = ATRuntimeEnvironment(abort_on_failure)
  3. Configure the communicator

    This is the component which will communicate with your device

    atrunenv.configure_communicator(device, baud_rate, default_timeout, line_break)
  4. Open the serial port

    Be careful, this function can return an ATSerialPortError

    atrunenv.open_serial()
  5. Choose how to parse commands:

    1. Parse an ATScript

      parse_ATScript can raise ATScriptNotFound or ATScriptSyntaxError

      atrunenv.parse_ATScript(script_file)
    2. Execute directly a command (or an ESK)

      response = atrunenv.exec(command_str)
    3. Add an ATCommand to the session

      atrunenv.add_command(command_str)
  6. Execute commands:

    1. Run everything at once and then get a list of ATResponse

      if abort_on_failure is True, the ATRE will raise ATRuntimeError during execution

      response_list = atrunenv.run()
    2. Run one command a time (if abort_on_failure is True, the ATRE will raise ATRuntimeError):

      response = atrunenv.exec_next()
  7. Collect the values you need

    rssi = atrunenv.get_session_value("rssi")
  8. Close serial

    atrunenv.close_serial()

Virtual Device ⌨

Since version 1.1.0, it is possible to use a virtual serial device, instead of a real one. This has been introduced for test purposes, but can actually be used in case you need to emulate a serial device and you want to keep using ATtila. In this case, in the ATRE, instead of using configure_communicator use:

def configure_virtual_communicator(self, serial_port, baud_rate, timeout = None, line_break = "\r\n", read_callback = None, write_callback = None, in_waiting_callback = None)

The virtual communicator, in addition to the standard one, requires a read, a write and an in_waiting callback. These callbacks must replace the I/O operations of the serial device, with something else (e.g. a socket with an HTTP request)

ATScripts πŸ’»

ATtila uses its own syntax to communicate with the serial device, which is called ATScript (ATS). The basic syntax for it, is:

COMMAND;;RESPONSE_EXPR;;DELAY;;TIMEOUT;;["COLLECTABLE1",...];;DOPPELGANGER;;DOPPELGANGER_RESPONSE

To know more about ATS see the ATScript documentation


Support the developer β˜•

If you like ATtila and you're grateful for the work I've done, please consider a little donation πŸ₯³

You can make a donation on the following platforms:

ko-fi PayPal bitcoin


Contributions 🀝🏻

Contributions are welcome! πŸ˜‰

If you think you can contribute to ATtila, please follow ATtila's Contributions Guidelines


Changelog πŸ•‘

View Changelog HERE


Branches 🌳

  • master: stable only with latest features
  • 1.1.x: LTS with Python3.4 support; this version will receive only patch for major issues
  • dev: main development branch
  • other features

License πŸ“œ

View LICENSE HERE

attila's People

Contributors

butlerpaul avatar veeso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

attila's Issues

sleep_time_based_on_baud leads to incomplete response..

Hi,

I have an AT command that returns long response (actually a json repr of a LwM2M object).
When I excecute it, I get an error be cause the decoded response is incomplete: the OK line as per expected response, is not catched by the exec.

More precisely, the missed lines are due to this loop:

while (
self._device.in_waiting == 0
and sleep_time_based_on_baud > t_waiting_elapsed
):
sleep(mini_sleep_time) # 1ms
t_waiting_elapsed += mini_sleep_time
# Check if there are still data available
if self._device.in_waiting > 0:
data_still_available = True
else:
data_still_available = False
data += read_bytes

Indeed, debugging shows that it did not wait "enough" for data to be ready i.e polling the condition self._device.in_waiting.
So I multiplied by 10 the sleeping time in the lines

sleep_time_based_on_baud = 100 / self.baud_rate # Milliseconds

to become

sleep_time_based_on_baud = 1000 / self.baud_rate  # Milliseconds 

To my understanding the inverse of baudrate (units in bits/sec) is to be multiplied by 1000 to convert to ms !
@veeso, what do you think ?

This said, I did not have an issue when the response size was small...

Cheers,
Roudy

[BUG] Bad response

Describe the bug
I often get bad response to the same command :

Exception :  "Command 'AT+CSQ' got a bad response: '['AT+CSQ']' (and hasn't any doppelganger)!"

To Reproduce
Run the following code

atrunenv = ATRuntimeEnvironment(True)
atrunenv.configure_communicator(serial_port="/dev/ttyUSB2", baud_rate=9600, timeout=5)
atrunenv.open_serial()
while True:
	print("Running command")
	try:
		response = atrunenv.exec("AT+CSQ;;OK;;0;;5;;['AT+CSQ=?{rssi},','AT+CSQ=${rssi},?{ber}']")
		print(response.full_response)
	except Exception as e:
		print("Exception : ", e)
	time.sleep(1)

Expected behavior
No exception since the command is correct and a timeout of 5 seconds should be sufficient. The sleep(1) makes sure to not run too many commands.

Desktop:

  • OS: Linux
  • Architecture ARM
  • Python 3.7.4
  • ATtila 1.1.4

[BUG] Strange behavior on Raspbian OS

Describe the bug
Hello! I have a Huawei ME909s modem. I wrote a test script and it works on Windows 11 pretty good, but on Raspbian OS Bullseye it acts weirdly.

To Reproduce

import os
from time import sleep
from attila.atre import ATRuntimeEnvironment


def main():
    res = ser.exec('AT^CURC=0')
    print(res.full_response)
    print(res.execution_time)
    res = ser.exec('AT^SYSCFGEX="02",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF,,')
    print(res.full_response)
    print(res.execution_time)
    sleep(5)
    res = ser.exec('AT^NETSCAN=20,-110,1')
    print(res.full_response)
    print(res.execution_time)


if os.name == 'nt':
    port = 'COM30'
else:
    port = "/dev/ttyUSB5"
ser = ATRuntimeEnvironment(abort_on_failure=True)
ser.configure_communicator(port, 128000, 60)
ser.open_serial()
main()
ser.close_serial()

Expected behavior
On Windows this code works as expected, I have answers to all commands from the modem:

['', 'OK']
15
['', 'OK']
14
['', '^NETSCAN: 2987,,,D2,257,02,0,-64,CF296D,2000000000000,52', '^NETSCAN: 10588,,,69,257,01,0,-68,E7AC7,400000,466', '^NETSCAN: 10638,,,69,257,01,0,-68,EA1D7,400000,466', '^NETSCAN: 10613,,,69,257,01,0,-69,E7ACD,400000,466', '^NETSCAN: 10563,,,69,257,01,0,-70,E7ACA,400000,466', '^NETSCAN: 10713,,,D2,257,02,0,-76,CF9B24,400000,384', '^NETSCAN: 10688,,,D2,257,02,0,-76,CF9B21,400000,384', '^NETSCAN: 10663,,,D2,257,02,0,-78,CF2C78,400000,191', '^NETSCAN: 3013,,,69,257,01,0,-80,EC777,2000000000000,209', '^NETSCAN: 10788,,,44C,257,04,0,-82,982DCC,400000,504', '^NETSCAN: 10738,,,D2,257,02,0,-82,CF9B27,400000,384', '^NETSCAN: 10763,,,44C,257,04,0,-82,9830A4,400000,385', '', 'OK']
38510 - this is normal, the modem always takes so long to respond to this command

But on Raspbian the modem answers only on the first command (AT^CURC=0) and then just returns my commands without asnwer:

['', 'OK']
499
['AT^SYSCFGEX="02",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF,,']
2
['AT^NETSCAN=20,-110,1,2000000000000']
3

if I run the script immediately again:

['AT^CURC=0']
498
['AT^SYSCFGEX="02",3FFFFFFF,1,2,7FFFFFFFFFFFFFFF,,', '', '^NETSCAN: 10638,,,69,257,01,0,-70,EA1D7,400000,466', '^NETSCAN: 10613,,,69,257,01,0,-71,E7ACD,400000,466', '^NETSCAN: 10713,,,D2,257,02,0,-71,CF9B24,400000,384', '^NETSCAN: 10688,,,D2,257,02,0,-71,CF9B21,400000,384', '^NETSCAN: 10663,,,D2,257,02,0,-74,CF3FE0,400000,384', '^NETSCAN: 10588,,,69,257,01,0,-74,E7AC9,400000,468', '^NETSCAN: 10763,,,44C,257,04,0,-77,982DCA,400000,505', '^NETSCAN: 10563,,,69,257,01,0,-78,E7ACC,400000,468', '', 'OK']
3
['AT^NETSCAN=20,-110,1']
3

then I get a response to the commands from the previous run. It looks like the script is not waiting for a response. I tried to use ATScripts like AT^CURC=0;;OK;;0;;30 to set timeout, but it did not help.

Desktop (please complete the following information):

  • OS: Raspbian OS Bullseye, Windows 11
  • Architecture: ARM / x86
  • Python version: 3.9.13
  • ATtila version: 1.2.0

[BUG] Longer Response time commands do not execute properly

Describe the bug
It appears that longer executing commands do not collect all the information from the output, e.g. commands such as AT+CGDCONT? and AT+COPS=?. Most of the time, the parser only catches the echo of the command and not the full response.

To Reproduce

atrunenv = ATRuntimeEnvironment(abort_on_failure=True)
atrunenv.configure_communicator(port_name, baud_rate)
atrunenv.open_serial()

# returns ['AT+CGDCONT?'] or ['AT+CGDCONT?', '', '+CGDCONT: 1,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0'], not all results
cgdcont_result = self.atrunenv.exec('AT+CGDCONT?')
# fails as it parses only the shortened results
cgdcont_result = self.atrunenv.exec('AT+CGDCONT?;;OK;;;;5')

# sometimes times out, sometimes gets the response if a recent scan - inconsistent
cops_result = self.atrunenv.exec('AT+COPS=?;;OK;;;;900')

Expected behavior
CGDCONT should capture all data, there were 3 other PDP contexts displayed normally. COPS should wait for the operator scan to complete and return the data.

Desktop (please complete the following information):

  • OS: Debian 32-bit
  • Architecture ARMHF
  • Python version 3.7
  • ATtila version 1.2.2

Additional context
There may be an additional consistency bug. Some of the normal commands failed with no output, but repeating the command succeeds. The CGDCONT always fails however.

[BUG] Abnormal execution time

Describe the bug
Very long execution time for at command AT+CSQ : about 3 seconds

To Reproduce
Run the following code :

atrunenv = ATRuntimeEnvironment(True)
atrunenv.configure_communicator(serial_port="/dev/ttyUSB2", baud_rate=9600, timeout=5)
atrunenv.open_serial()
response = atrunenv.exec("AT+CSQ;;OK;;0;;;;['AT+CSQ=?{rssi},','AT+CSQ=${rssi},?{ber}']")
print(response.full_response)
print(response.execution_time)

Expected behavior
An execution time lesser than 1 seconds

Desktop (please complete the following information):

  • OS: Linux
  • Architecture ARM
  • Python version 3.7.4
  • ATtila version 1.1.3

Additional context
The command used below (AT+CSQ) ran through a minicom returns instantly.
The same code with command "AT;;OK;;0" takes about 950ms, which is also quite high.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.