Skip to content

Commit a57c2a6

Browse files
committed
Hologram Python SDK v0.7.5 release
1 parent 64a934d commit a57c2a6

File tree

12 files changed

+96
-29
lines changed

12 files changed

+96
-29
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# What's New in Hologram Python SDK
22

3+
## v0.7.5
4+
5+
2018-02-13 Hologram <[email protected]>
6+
* Force persistent connection for hologram spacebridge
7+
* hologram spacebridge no longer sets default route
8+
* Remove redundant manifest includes
9+
10+
2018-02-06 Hologram <[email protected]>
11+
* Increase socket connect and write timeouts
12+
13+
2018-02-05 Hologram <[email protected]>
14+
* Fix infinite loop in `send_message`
15+
16+
## v0.7.4
17+
18+
2018-01-08 Hologram <[email protected]>
19+
* Just a bunch of internal tool changes. Happy New Year! :)
20+
321
## v0.7.3
422

523
2018-01-04 Hologram <[email protected]>

Hologram/Cloud.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from Network import NetworkManager
1414
from Authentication import *
1515

16-
__version__ = '0.7.4'
16+
__version__ = '0.7.5'
1717

1818
class Cloud(object):
1919

Hologram/Network/Cellular.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010

1111
from ..Event import Event
1212
from Exceptions.HologramError import NetworkError
13+
from Hologram.Network.Route import Route
1314
from Modem import Modem
1415
from Modem import E303
1516
from Modem import MS2131
1617
from Modem import Nova_U201
1718
from Modem import NovaM_R404
18-
from Network import Network
19-
import subprocess
19+
from Network import Network, NetworkScope
2020
import time
2121
import usb.core
2222

@@ -43,6 +43,7 @@ def __init__(self, event=Event()):
4343
super(Cellular, self).__init__(event=event)
4444
self._connection_status = CLOUD_DISCONNECTED
4545
self._modem = None
46+
self._route = Route()
4647

4748
def autodetect_modem(self):
4849
# scan for a modem and set it if found
@@ -66,11 +67,13 @@ def connect(self, timeout = DEFAULT_CELLULAR_TIMEOUT):
6667
except KeyboardInterrupt as e:
6768
pass
6869

70+
6971
if success:
7072
self.logger.info('Successfully connected to cell network')
7173
# Disable at sockets mode since we're already establishing PPP.
7274
# This call is needed in certain modems that have limited interfaces to work with.
7375
self.disable_at_sockets_mode()
76+
self.__configure_routing()
7477
self._connection_status = CLOUD_CONNECTED
7578
self.event.broadcast('cellular.connected')
7679
super(Cellular, self).connect()
@@ -144,6 +147,13 @@ def popReceivedSMS(self):
144147
def get_sim_otp_response(self, command):
145148
return self.modem.get_sim_otp_response(command)
146149

150+
def __configure_routing(self):
151+
self.logger.info('Adding routes to Hologram cloud')
152+
self._route.add('10.176.0.0/16', self.localIPAddress)
153+
self._route.add('10.254.0.0/16', self.localIPAddress)
154+
if self.scope == NetworkScope.SYSTEM:
155+
self.logger.info('Adding system-wide default route to cellular interface')
156+
self._route.add_default(self.localIPAddress)
147157

148158
def _scan_for_modems(self):
149159
res = None

Hologram/Network/Modem/Modem.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import pyudev
2525
import serial
2626
import time
27+
from serial.serialutil import Timeout
2728

2829
DEFAULT_CHATSCRIPT_PATH = '/chatscripts/default-script'
2930

@@ -33,6 +34,9 @@ class Modem(IModem):
3334
DEFAULT_SERIAL_READ_SIZE = 256
3435
DEFAULT_SERIAL_TIMEOUT = 1
3536
DEFAULT_SERIAL_RETRIES = 0
37+
DEFAULT_SEND_TIMEOUT = 10
38+
39+
_RETRY_DELAY = 0.05 # 50 millisecond delay to avoid spinning loops
3640

3741
SOCKET_INIT = 0
3842
SOCKET_WRITE_STATE = 1
@@ -232,14 +236,19 @@ def set_network_registration_status(self):
232236
def reset(self):
233237
self.set('+CFUN', '16') # restart the modem
234238

235-
def send_message(self, data):
239+
def send_message(self, data, timeout=DEFAULT_SEND_TIMEOUT):
236240

237241
self.urc_state = Modem.SOCKET_INIT
238242

239243
self.write_socket(data)
240244

245+
loop_timeout = Timeout(timeout)
241246
while self.urc_state != Modem.SOCKET_SEND_READ:
242247
self.checkURC()
248+
if self.urc_state != Modem.SOCKET_SEND_READ:
249+
if loop_timeout.expired():
250+
raise SerialError('Timeout occurred waiting for message status')
251+
time.sleep(self._RETRY_DELAY)
243252

244253
return self.read_socket()
245254

@@ -269,7 +278,7 @@ def create_socket(self):
269278
# EFFECTS: Issues an AT command to connect to the specified socket identifier.
270279
def connect_socket(self, host, port):
271280
at_command_val = "%d,\"%s\",%s" % (self.socket_identifier, host, port)
272-
ok, _ = self.set('+USOCO', at_command_val, timeout=5)
281+
ok, _ = self.set('+USOCO', at_command_val, timeout=20)
273282
if ok != ModemResult.OK:
274283
self.logger.error('Failed to connect socket')
275284
else:
@@ -287,7 +296,7 @@ def write_socket(self, data):
287296

288297
self.enable_hex_mode()
289298
value = '%d,%s,\"%s\"' % (self.socket_identifier, len(data), binascii.hexlify(data))
290-
ok, _ = self.set('+USOWR', value)
299+
ok, _ = self.set('+USOWR', value, timeout=10)
291300
if ok != ModemResult.OK:
292301
self.logger.error('Failed to write to socket')
293302
self.disable_hex_mode()

Hologram/Network/Modem/ModemMode/PPP.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def connect(self, timeout=DEFAULT_PPP_TIMEOUT):
4646

4747
if result == True and self.route.wait_for_interface(DEFAULT_PPP_INTERFACE,
4848
MAX_PPP_INTERFACE_UP_RETRIES):
49-
self.__reroute_packets()
5049
return True
5150
else:
5251
return False
@@ -92,16 +91,6 @@ def __check_for_existing_ppp_sessions(self):
9291

9392
return existing_ppp_pids
9493

95-
def __reroute_packets(self):
96-
self.logger.info('Rerouting packets to %s interface', DEFAULT_PPP_INTERFACE)
97-
# Make sure that we still have ppp interface before adding the routes.
98-
ppp_available = self.route.wait_for_interface(DEFAULT_PPP_INTERFACE, MAX_REROUTE_PACKET_RETRIES)
99-
if not ppp_available:
100-
return
101-
self.route.add('10.176.0.0/16', self.localIPAddress)
102-
self.route.add('10.254.0.0/16', self.localIPAddress)
103-
self.route.add_default(self.localIPAddress)
104-
10594
@property
10695
def localIPAddress(self):
10796
return self._ppp.raddr

Hologram/Network/Network.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99
#
1010

1111
from Hologram.Event import Event
12-
import os
1312
import logging
1413
from logging import NullHandler
14+
from enum import Enum
15+
16+
17+
class NetworkScope(Enum):
18+
SYSTEM = 1
19+
HOLOGRAM = 2
20+
1521

1622
class Network(object):
1723

@@ -23,6 +29,7 @@ def __init__(self, event=Event()):
2329
# Logging setup.
2430
self.logger = logging.getLogger(__name__)
2531
self.logger.addHandler(NullHandler())
32+
self.scope = NetworkScope.SYSTEM
2633

2734
def connect(self):
2835
self.event.broadcast('network.connected')

MANIFEST.in

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
include AUTHORS
21
include LICENSE
3-
include ChangeLog
42
include MANIFEST.in
53
include Makefile
64
include requirements.txt

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
enum34==1.1.6
12
hjson==2.0.2
23
mock==2.0.0
34
pyroute2==0.4.21

scripts/hologram_receive.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
# LICENSE: Distributed under the terms of the MIT License
1010

1111
from Hologram.HologramCloud import HologramCloud
12-
from hologram_util import handle_timeout
1312
from hologram_util import handle_polling
1413
from hologram_util import VAction
1514
import sys
@@ -32,12 +31,17 @@ def popReceivedSMS():
3231
if recv is not None:
3332
print 'Received SMS:', recv
3433

35-
def parse_hologram_receive_args(parser):
34+
35+
def parse_common_receive_args(parser):
3636
parser.add_argument('-m', '--modem', nargs='?', default='nova',
3737
help='The modem type. Choose between nova, ms2131 and e303.')
3838
parser.add_argument('-v', nargs='?', action=VAction, dest='verbose', required=False)
3939
parser.add_argument('-t', '--timeout', type=int, nargs='?', default=-1,
4040
help='The number of seconds before the socket is closed. Default is to block indefinitely.')
41+
42+
43+
def parse_hologram_receive_args(parser):
44+
parse_common_receive_args(parser)
4145
parse_data_args(parser)
4246
parse_sms_args(parser)
4347

scripts/hologram_spacebridge.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,45 @@
1010
#
1111
# LICENSE: Distributed under the terms of the MIT License
1212

13+
from Hologram.HologramCloud import HologramCloud
14+
from Hologram.Network import NetworkScope
15+
from hologram_util import handle_polling
16+
from scripts.hologram_receive import parse_common_receive_args
17+
import sys
18+
19+
# pylint: disable=W0603
20+
hologram = None
21+
22+
23+
def popReceivedMessage():
24+
recv = hologram.popReceivedMessage()
25+
if recv is not None:
26+
print('Received message: ' + str(recv))
1327

14-
from scripts.hologram_receive import run_hologram_receive
15-
from scripts.hologram_receive import parse_hologram_receive_args
1628

1729
def parse_hologram_spacebridge_args(parser):
18-
parse_hologram_receive_args(parser)
30+
parse_common_receive_args(parser)
1931
parser.set_defaults(command_selected='spacebridge')
2032

33+
2134
def run_hologram_spacebridge(args):
22-
args['command_selected'] = 'receive_data'
23-
run_hologram_receive(args)
35+
global hologram
36+
hologram = HologramCloud(dict(), network='cellular')
37+
38+
hologram.event.subscribe('message.received', popReceivedMessage)
39+
40+
hologram.network.disable_at_sockets_mode() # Persistent cellular connection
41+
hologram.network.scope = NetworkScope.HOLOGRAM # Default route NOT set to cellular
42+
hologram.network.connect()
43+
44+
hologram.openReceiveSocket()
45+
print ('Ready to receive data on port %s' % hologram.receive_port)
46+
47+
try:
48+
handle_polling(args['timeout'], popReceivedMessage, 1)
49+
except KeyboardInterrupt as e:
50+
print('Closing socket...')
51+
hologram.closeReceiveSocket()
52+
sys.exit(e)
53+
finally:
54+
hologram.network.disconnect()

0 commit comments

Comments
 (0)