Skip to content

Commit

Permalink
Merge 78138f1 into 86a497c
Browse files Browse the repository at this point in the history
  • Loading branch information
ocalvo committed Jun 12, 2020
2 parents 86a497c + 78138f1 commit a52fc01
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 1 deletion.
5 changes: 5 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2.13
====

* Add support for asyncio in the gammu worker

2.12
====

Expand Down
122 changes: 122 additions & 0 deletions examples/async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# vim: expandtab sw=4 ts=4 sts=4:
#
# Copyright © 2003 - 2018 Michal Čihař <michal@cihar.com>
#
# This file is part of python-gammu <https://wammu.eu/python-gammu/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
python-gammu - Phone communication libary
Gammu asynchronous wrapper example with asyncio. This allows your application to care
only about handling received data and not about phone communication
details.
'''

import sys
import pprint
pp = pprint.PrettyPrinter(indent=4)

import gammu
import gammu.asyncworker
import asyncio


def sms_callback(messages):
pp.pprint(messages)

async def send_message_async(state_machine, number, message):
smsinfo = {
'Class': -1,
'Unicode': False,
'Entries': [
{
'ID': 'ConcatenatedTextLong',
'Buffer': message
}
]}
# Encode messages
encoded = gammu.EncodeSMS(smsinfo)
# Send messages
for message in encoded:
# Fill in numbers
message['SMSC'] = {'Location': 1}
message['Number'] = number
# Actually send the message
await state_machine.send_sms_async(message)

async def get_network_info(worker):
info = await worker.GetNetworkInfoAsync()
print('NetworkName:',info['NetworkName'])
print(' State:',info['State'])
print(' NetworkCode:',info['NetworkCode'])
print(' CID:',info['CID'])
print(' LAC:',info['LAC'])

async def get_info(state_machine):
print('Phone infomation:')
manufacturer = await state_machine.GetManufacturer()
print(('{0:<15}: {1}'.format('Manufacturer', manufacturer)))
model = await state_machine.GetModel()
print(('{0:<15}: {1} ({2})'.format('Model', model[0], model[1])))
imei = await state_machine.GetIMEI()
print(('{0:<15}: {1}'.format('IMEI', imei)))
firmware = await state_machine.GetFirmware()
print(('{0:<15}: {1}'.format('Firmware', firmware[0])))

async def main():

gammu.SetDebugFile(sys.stderr)
gammu.SetDebugLevel('textall')

config = dict(Device="/dev/ttyS6", Connection="at")
worker = gammu.asyncworker.GammuAsyncWorker()
worker.configure(config)

try:
await worker.init_async()

print(await worker.get_signal_quality_async())

await send_message_async(worker, '6700', 'BAL')

# Just a busy waiting for event
# We need to keep communication with phone to get notifications
print('Press Ctrl+C to interrupt')
while 1:
try:
signal = await worker.get_signal_quality_async()
print('Signal is at {0:d}%'.format(signal['SignalPercent']))
except Exception as e:
print('Exception reading signal: {0}'.format(e))

await asyncio.sleep(30)

except Exception as e:
print('Exception:')
print(e)

print("Terminate Start")
await worker.terminate_async()
print("Terminate Done")

if __name__ == '__main__':
event_loop = asyncio.get_event_loop()
try:
event_loop.run_until_complete(main())
finally:
event_loop.close()

1 change: 1 addition & 0 deletions gammu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
__all__ = [
'data',
'worker',
'asyncworker',
'smsd',
'exception',
]
117 changes: 117 additions & 0 deletions gammu/asyncworker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Async extensions for gammu."""
import asyncio
from asyncio import get_running_loop

import gammu # pylint: disable=import-error, no-member
import gammu.worker # pylint: disable=import-error, no-member

class GammuAsyncThread(gammu.worker.GammuThread):
"""Thread for phone communication."""

def __init__(self, queue, config, callback):
"""Initialize thread."""
super().__init__(queue, config, callback)

def _do_command(self, future, cmd, params, percentage=100):
"""Execute single command on phone."""
func = getattr(self._sm, cmd)
result = None
try:
if params is None:
result = func()
elif isinstance(params, dict):
result = func(**params)
else:
result = func(*params)
except gammu.GSMError as info:
errcode = info.args[0]["Code"]
error = gammu.ErrorNumbers[errcode]
self._callback(future, result, error, percentage)
except Exception as exception: # pylint: disable=broad-except
self._callback(future, None, exception, percentage)
else:
self._callback(future, result, None, percentage)


class GammuAsyncWorker(gammu.worker.GammuWorker):
"""Extend gammu worker class for async operations."""

def worker_callback(self, name, result, error, percents):
"""Execute command from the thread worker."""
future = None
if name == "Init" and self._init_future is not None:
future = self._init_future
elif name == "Terminate" and self._terminate_future is not None:
# Set _kill to true on the base class to avoid waiting for termination
self._thread._kill = True # pylint: disable=protected-access
future = self._terminate_future
elif hasattr(name, "set_result"):
future = name

if future is not None:
if error is None:
self._loop.call_soon_threadsafe(future.set_result, result)
else:
exception = error
if not isinstance(error, Exception):
exception = gammu.GSMError(error)
self._loop.call_soon_threadsafe(future.set_exception, exception)

def __init__(self):
"""Initialize the worker class.
@param callback: See L{GammuThread.__init__} for description.
"""
super().__init__(self.worker_callback)
self._loop = get_running_loop()
self._init_future = None
self._terminate_future = None
self._thread = None

async def init_async(self):
"""Connect to phone."""
self._init_future = self._loop.create_future()

self._thread = GammuAsyncThread(self._queue, self._config, self._callback)
self._thread.start()

await self._init_future
self._init_future = None

async def get_signal_quality_async(self):
"""Get signal quality from phone."""
future = self._loop.create_future()
self.enqueue(future, commands=[("GetSignalQuality", ())])
result = await future
return result

async def send_sms_async(self, message):
"""Send sms message via the phone."""
future = self._loop.create_future()
self.enqueue(future, commands=[("SendSMS", [message])])
result = await future
return result

async def set_incoming_callback_async(self, callback):
"""Set the callback to call from phone."""
future = self._loop.create_future()
self.enqueue(future, commands=[("SetIncomingCallback", [callback])])
result = await future
return result

async def set_incoming_sms_async(self):
"""Activate SMS notifications from phone."""
future = self._loop.create_future()
self.enqueue(future, commands=[("SetIncomingSMS", ())])
result = await future
return result

async def terminate_async(self):
"""Terminate phone communication."""
self._terminate_future = self._loop.create_future()
self.enqueue("Terminate")
await self._terminate_future

while self._thread.is_alive():
await asyncio.sleep(5)
self._thread = None
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import sys

# some defines
VERSION = '2.12'
VERSION = '2.13'
GAMMU_REQUIRED = '1.37.90'
README_FILE = os.path.join(os.path.dirname(__file__), 'README.rst')
with codecs.open(README_FILE, 'r', 'utf-8') as readme:
Expand Down

0 comments on commit a52fc01

Please sign in to comment.