Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up code base, make module simpler #49

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Hologram/Api/Api.py → Hologram/Api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import logging
from logging import NullHandler

from Exceptions.HologramError import ApiError
from Hologram.Exceptions import ApiError
import requests

HOLOGRAM_REST_API_BASEURL = 'https://dashboard.hologram.io/api/1'
Expand Down
1 change: 0 additions & 1 deletion Hologram/Api/__init__.py

This file was deleted.

2 changes: 1 addition & 1 deletion Hologram/Authentication/CSRPSKAuthentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# LICENSE: Distributed under the terms of the MIT License
#
import json
from Exceptions.HologramError import AuthenticationError
from Hologram.Exceptions import AuthenticationError
from Hologram.Authentication.HologramAuthentication import HologramAuthentication

DEVICE_KEY_LEN = 8
Expand Down
43 changes: 28 additions & 15 deletions Hologram/Cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import logging
from logging import NullHandler
from Hologram.Event import Event
from Hologram.Network import NetworkManager
from Hologram.Network import Network
from Hologram.Exceptions import NetworkError
from Hologram.Authentication import *

__version__ = '0.9.0'
Expand All @@ -21,7 +22,7 @@ def __repr__(self):
return type(self).__name__

def __init__(self, credentials, send_host = '', send_port = 0,
receive_host = '', receive_port = 0, network = ''):
receive_host = '', receive_port = 0):

# Logging setup.
self.logger = logging.getLogger(__name__)
Expand All @@ -33,25 +34,30 @@ def __init__(self, credentials, send_host = '', send_port = 0,
self.__initialize_host_and_port(send_host, send_port,
receive_host, receive_port)

self.initializeNetwork(network)
self.initializeNetwork()

def __initialize_host_and_port(self, send_host, send_port, receive_host, receive_port):
self.send_host = send_host
self.send_port = send_port
self.receive_host = receive_host
self.receive_port = receive_port

def initializeNetwork(self, network):
def initializeNetwork(self):

self.event = Event()
self.__message_buffer = []

# Network Configuration
self._networkManager = NetworkManager.NetworkManager(self.event, network)
self._network = Network(self.event)

try:
self._network.autodetect_modem()
except NetworkError as e:
self.logger.info("No modem found. Loading drivers and retrying")
self._network.load_modem_drivers()
self._network.autodetect_modem()

# This registers the message buffering feature based on network availability.
self.event.subscribe('network.connected', self.__clear_payload_buffer)
self.event.subscribe('network.disconnected', self._networkManager.networkDisconnected)
self.event.subscribe('cellular.connected', self.__clear_payload_buffer)

# EFFECTS: Adds the given payload to the buffer
def addPayloadToBuffer(self, payload):
Expand All @@ -60,7 +66,6 @@ def addPayloadToBuffer(self, payload):
# EFFECTS: Tells the network manager that it is connected and clears all buffered
# messages by sending them to the cloud.
def __clear_payload_buffer(self):
self._networkManager.networkConnected()
for payload in self.__message_buffer:

recv = self.sendMessage(payload)
Expand Down Expand Up @@ -138,11 +143,19 @@ def event(self):
def event(self, event):
self._event = event

@property
def network_type(self):
return repr(self._networkManager)

# Returns the network instance itself.
@property
def network(self):
return self._networkManager.network
return self._network

@network.setter
def network(self, network, modem=None):
self.network = network

if modem is not None:
self._network.modem = modem
try:
self._network.autodetect_modem()
except NetworkError as e:
self.logger.info("No modem found. Loading drivers and retrying")
self._network.load_modem_drivers()
self._network.autodetect_modem()
13 changes: 4 additions & 9 deletions Hologram/CustomCloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@

from collections import deque
import socket
import sys
import threading
import time
from Hologram.Cloud import Cloud
from Exceptions.HologramError import HologramError
from Hologram.Exceptions import HologramError

MAX_RECEIVE_BYTES = 1024
MAX_QUEUED_CONNECTIONS = 5
Expand All @@ -24,15 +22,13 @@
class CustomCloud(Cloud):

def __init__(self, credentials, send_host='', send_port=0,
receive_host='', receive_port=0, enable_inbound=False,
network=''):
receive_host='', receive_port=0, enable_inbound=False):

super().__init__(credentials,
send_host=send_host,
send_port=send_port,
receive_host=receive_host,
receive_port=receive_port,
network=network)
receive_port=receive_port)

# Enforce that the send and receive configs are set before using the class.
if enable_inbound and (receive_host == '' or receive_port == 0):
Expand Down Expand Up @@ -383,8 +379,7 @@ def _enforce_minimum_periodic_interval(self, interval):
raise HologramError('Interval cannot be less than %d seconds.' % MIN_PERIODIC_INTERVAL)

def __enforce_network_disconnected(self):
if self.network_type == 'Cellular':
self.network.disconnect()
self.network.disconnect()

def getResultString(self, result_code):
return str(result_code)
Expand Down
File renamed without changes.
2 changes: 0 additions & 2 deletions Hologram/Event/__init__.py

This file was deleted.

File renamed without changes.
7 changes: 3 additions & 4 deletions Hologram/HologramCloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from Hologram.CustomCloud import CustomCloud
from HologramAuth import TOTPAuthentication, SIMOTPAuthentication
from Hologram.Authentication import CSRPSKAuthentication
from Exceptions.HologramError import HologramError
from Hologram.Exceptions import HologramError

DEFAULT_SEND_MESSAGE_TIMEOUT = 5
HOLOGRAM_HOST_SEND = 'cloudsocket.hologram.io'
Expand Down Expand Up @@ -59,15 +59,14 @@ class HologramCloud(CustomCloud):
ERR_UNKNOWN: 'Unknown error'
}

def __init__(self, credentials, enable_inbound=False, network='',
def __init__(self, credentials, enable_inbound=False,
authentication_type='totp'):
super().__init__(credentials,
send_host=HOLOGRAM_HOST_SEND,
send_port=HOLOGRAM_PORT_SEND,
receive_host=HOLOGRAM_HOST_RECEIVE,
receive_port=HOLOGRAM_PORT_RECEIVE,
enable_inbound=enable_inbound,
network=network)
enable_inbound=enable_inbound)

self.setAuthenticationType(credentials, authentication_type=authentication_type)

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# LICENSE: Distributed under the terms of the MIT License
#

from Hologram.Network.Modem import Modem
from Hologram.Modem import Modem
from Hologram.Event import Event

DEFAULT_E303_TIMEOUT = 200
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# LICENSE: Distributed under the terms of the MIT License
#

from Hologram.Network.Modem import Modem
from Hologram.Modem import Modem
from Hologram.Event import Event

DEFAULT_E372_TIMEOUT = 200
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# LICENSE: Distributed under the terms of the MIT License
#

from Hologram.Network.Modem import Modem
from Hologram.Modem import Modem
from Hologram.Event import Event

DEFAULT_MS2131_TIMEOUT = 200
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

from serial.serialutil import Timeout

from Hologram.Network.Modem import Modem
from Hologram.Modem import Modem
from Hologram.Event import Event
from UtilClasses import ModemResult
from Exceptions.HologramError import SerialError, NetworkError
from Hologram.Utils import ModemResult
from Hologram.Exceptions import SerialError, NetworkError

DEFAULT_BG96_TIMEOUT = 200

Expand Down
169 changes: 169 additions & 0 deletions Hologram/Modem/SIMCom/SIM7000.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# SIM7000.py - Hologram Python SDK SIMCom SIM7000 modem interface
#
# Author: Hologram <[email protected]>
#
# Copyright 2016 - Hologram (Konekt, Inc.)
#
#
# LICENSE: Distributed under the terms of the MIT License
#
import binascii
import time

from serial.serialutil import Timeout

from Hologram.Modem import Modem
from Hologram.Event import Event
from Hologram.Utils import ModemResult
from Hologram.Exceptions import SerialError, NetworkError

DEFAULT_SIM7000_TIMEOUT = 200

class SIM7000(Modem):
usb_ids = [('1e0e', '9001')]

def __init__(self, device_name=None, baud_rate='9600',
chatscript_file=None, event=Event()):

super().__init__(device_name=device_name, baud_rate=baud_rate,
chatscript_file=chatscript_file, event=event)
self._at_sockets_available = True
self.urc_response = ''

def connect(self, timeout=DEFAULT_SIM7000_TIMEOUT):

success = super().connect(timeout)

# put serial mode on other port
if success is True:
# detect another open serial port to use for PPP
devices = self.detect_usable_serial_port()
if not devices:
raise SerialError('Not enough serial ports detected for Nova')
self.logger.debug('Moving connection to port %s', devices[0])
self.device_name = devices[0]
super().initialize_serial_interface()

return success

def send_message(self, data, timeout=Modem.DEFAULT_SEND_TIMEOUT):
# Waiting for the open socket urc
while self.urc_state != Modem.SOCKET_WRITE_STATE:
self.checkURC()

self.write_socket(data)

loop_timeout = Timeout(timeout)
while self.urc_state != Modem.SOCKET_SEND_READ:
self.checkURC()
if self.urc_state != Modem.SOCKET_SEND_READ:
if loop_timeout.expired():
raise SerialError('Timeout occurred waiting for message status')
time.sleep(self._RETRY_DELAY)
elif self.urc_state == Modem.SOCKET_CLOSED:
return '[1,0]' #this is connection closed for hologram cloud response

return self.urc_response

def create_socket(self):
self._set_up_pdp_context()

def connect_socket(self, host, port):
self.command('+CIPSTART', '\"TCP\",\"%s\",%d' % (host, port))

def close_socket(self, socket_identifier=None):
ok, _ = self.command('+CIPCLOSE')
if ok != ModemResult.OK:
self.logger.error('Failed to close socket')
self.urc_state = Modem.SOCKET_CLOSED

def write_socket(self, data):
hexdata = binascii.hexlify(data)
# We have to do it in chunks of 510 since 512 is actually too long (CMEE error)
# and we need 2n chars for hexified data
for chunk in self._chunks(hexdata, 510):
value = '%d,\"%s\"' % (self.socket_identifier, chunk.decode())
ok, _ = self.command('+CIPSEND', len(value), timeout=10, expected="SEND OK", prompt=">", data=value)
if ok != ModemResult.OK:
self.logger.error('Failed to write to socket')
raise NetworkError('Failed to write to socket')

def read_socket(self, socket_identifier=None, payload_length=None):
if payload_length is None:
payload_length = self.last_read_payload_length

ok, resp = self.set('+CIPRXGET', '1,%d' % (payload_length))
if ok == ModemResult.OK:
if resp is not None:
resp = resp.strip('"')
try:
resp = resp.decode()
except:
# This is some sort of binary data that can't be decoded so just
# return the bytes. We might want to make this happen via parameter
# in the future so it is more deterministic
self.logger.debug('Could not decode recieved data')

return resp

def is_registered(self):
return self.check_registered('+CREG') or self.check_registered('+CEREG')

def checkURC(self, hide=False):
# Not all SIMCOM urcs have a + in front
while(True):
response = self._readline_from_serial_port(0, hide=hide)
if len(response) > 0 and (response.startswith('+') or response in ['CONNECT', 'CONNECT OK', 'CONNECT FAIL', 'SEND OK', 'ALREADY CONNECT', 'CLOSED']):
urc = response.rstrip('\r\n')
self.handleURC(urc)
else:
return

def handleURC(self, urc):
if urc == 'CONNECT OK':
self.urc_state = Modem.SOCKET_WRITE_STATE
if urc == 'CLOSED':
self.urc_state = Modem.SOCKET_CLOSED
super().handleURC(urc)

def _is_pdp_context_active(self):
if not self.is_registered():
return False

ok, r = self.command('+CIPSTATUS', expected="STATE: IP START")
return ok == ModemResult.OK

def init_serial_commands(self):
self.command("E0") #echo off
self.command("+CMEE", "2") #set verbose error codes
self.command("+CPIN?")
self.set_timezone_configs()
#self.command("+CPIN", "") #set SIM PIN
self.command("+CPMS", "\"ME\",\"ME\",\"ME\"")
self.command("+CNMP", "38")
self.command("+CMNB", "1")
self.set_sms_configs()
self.set_network_registration_status()

def set_network_registration_status(self):
self.command("+CREG", "2")
self.command("+CEREG", "2")

def _set_up_pdp_context(self):
if self._is_pdp_context_active(): return True
ok, _ = self.command('+CIPSTATUS', expected="STATE: IP INITIAL")
while ok != ModemResult.OK:
self.command('+CIPSHUT')
ok, _ = self.command('+CIPSTATUS', expected="STATE: IP INITIAL")

self.set('+CSTT', '\"hologram\"')
self.command('+CIICR', timeout=30)
if not self._is_pdp_context_active():
self.logger.error('PDP Context setup failed')
raise NetworkError('Failed PDP context setup')
else:
self.logger.info('PDP context active')

@property
def description(self):
return 'SIMCom SIM7000'
2 changes: 2 additions & 0 deletions Hologram/Modem/SIMCom/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@


Loading