From 025b8f546d31ee0f37df928f22b9013f0e583569 Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Tue, 14 Jul 2020 18:18:08 -0500 Subject: [PATCH 01/23] major refactor --- Hologram/Api/Api.py | 2 +- .../Authentication/CSRPSKAuthentication.py | 2 +- Hologram/CustomCloud.py | 4 +- Hologram/{Event => }/Event.py | 0 Hologram/Event/__init__.py | 2 - .../Exceptions}/HologramError.py | 0 .../Exceptions}/__init__.py | 0 Hologram/HologramCloud.py | 2 +- Hologram/{Network => }/Modem/DriverLoader.py | 0 .../{Network/Modem => Modem/Huawei}/E303.py | 2 +- .../{Network/Modem => Modem/Huawei}/E372.py | 2 +- .../{Network/Modem => Modem/Huawei}/MS2131.py | 2 +- Hologram/Modem/Huawei/init.py | 0 .../{Network/Modem => Modem/Quectel}/BG96.py | 6 +- Hologram/Modem/Quectel/init.py | 0 Hologram/Modem/UBlox/Nova.py | 90 +++++++++++ .../{Network/Modem => Modem/UBlox}/NovaM.py | 6 +- .../Modem => Modem/UBlox}/Nova_U201.py | 8 +- Hologram/Modem/UBlox/init.py | 0 .../Modem/Modem.py => Modem/__init__.py} | 149 +++++++++--------- .../Modem/chatscripts/__init__.py | 0 .../Modem/chatscripts/default-script | 0 Hologram/{Network/Cellular.py => Network.py} | 31 ++-- Hologram/Network/BLE.py | 22 --- Hologram/Network/Ethernet.py | 39 ----- Hologram/Network/Modem/IModem.py | 126 --------------- Hologram/Network/Modem/MockModem.py | 23 --- Hologram/Network/Modem/ModemMode/IPPP.py | 34 ---- Hologram/Network/Modem/ModemMode/__init__.py | 4 - Hologram/Network/Modem/Nova.py | 33 ---- Hologram/Network/Modem/__init__.py | 4 - Hologram/Network/Network.py | 62 -------- Hologram/Network/NetworkManager.py | 84 ---------- Hologram/Network/Wifi.py | 67 -------- Hologram/Network/__init__.py | 3 - .../{Network/Modem/ModemMode => PPP}/PPP.py | 8 +- .../ModemMode.py => PPP/__init__.py} | 27 +++- .../{Network/Modem/ModemMode => PPP}/pppd.py | 2 +- Hologram/{Network => Utils}/Route.py | 0 .../Utils/__init__.py | 3 +- Hologram/__init__.py | 1 - ISSUE_TEMPLATE.md | 34 ---- UtilClasses/__init__.py | 2 - scripts/hologram | 2 +- scripts/hologram_activate.py | 2 +- scripts/hologram_modem.py | 2 +- scripts/hologram_network.py | 2 +- scripts/hologram_send.py | 2 +- .../test_CSRPSKAuthentication.py | 7 - tests/Modem/Huawei/test_E303.py | 67 ++++++++ tests/Modem/Huawei/test_E372.py | 67 ++++++++ tests/Modem/{ => Huawei}/test_MS2131.py | 2 +- tests/Modem/Quectel/test_BG96.py | 67 ++++++++ tests/Modem/{ => UBlox}/test_Nova.py | 2 +- tests/Modem/{ => UBlox}/test_NovaM.py | 2 +- tests/Modem/{ => UBlox}/test_NovaU201.py | 2 +- tests/Modem/test_Modem.py | 6 +- .../Modem/ModemMode => tests/PPP}/MockPPP.py | 8 +- tests/PPP/init.py | 0 .../test_ModemMode.py => PPP/test_IPPP.py} | 6 +- tests/{ModemMode => PPP}/test_PPP.py | 2 +- tests/init.py | 0 62 files changed, 453 insertions(+), 681 deletions(-) rename Hologram/{Event => }/Event.py (100%) delete mode 100644 Hologram/Event/__init__.py rename {Exceptions => Hologram/Exceptions}/HologramError.py (100%) rename {Exceptions => Hologram/Exceptions}/__init__.py (100%) rename Hologram/{Network => }/Modem/DriverLoader.py (100%) rename Hologram/{Network/Modem => Modem/Huawei}/E303.py (96%) rename Hologram/{Network/Modem => Modem/Huawei}/E372.py (96%) rename Hologram/{Network/Modem => Modem/Huawei}/MS2131.py (96%) create mode 100644 Hologram/Modem/Huawei/init.py rename Hologram/{Network/Modem => Modem/Quectel}/BG96.py (97%) create mode 100644 Hologram/Modem/Quectel/init.py create mode 100644 Hologram/Modem/UBlox/Nova.py rename Hologram/{Network/Modem => Modem/UBlox}/NovaM.py (95%) rename Hologram/{Network/Modem => Modem/UBlox}/Nova_U201.py (96%) create mode 100644 Hologram/Modem/UBlox/init.py rename Hologram/{Network/Modem/Modem.py => Modem/__init__.py} (91%) rename Hologram/{Network => }/Modem/chatscripts/__init__.py (100%) rename Hologram/{Network => }/Modem/chatscripts/default-script (100%) mode change 100755 => 100644 rename Hologram/{Network/Cellular.py => Network.py} (93%) delete mode 100644 Hologram/Network/BLE.py delete mode 100644 Hologram/Network/Ethernet.py delete mode 100644 Hologram/Network/Modem/IModem.py delete mode 100644 Hologram/Network/Modem/MockModem.py delete mode 100755 Hologram/Network/Modem/ModemMode/IPPP.py delete mode 100644 Hologram/Network/Modem/ModemMode/__init__.py delete mode 100644 Hologram/Network/Modem/Nova.py delete mode 100644 Hologram/Network/Modem/__init__.py delete mode 100644 Hologram/Network/Network.py delete mode 100644 Hologram/Network/NetworkManager.py delete mode 100644 Hologram/Network/Wifi.py delete mode 100644 Hologram/Network/__init__.py rename Hologram/{Network/Modem/ModemMode => PPP}/PPP.py (94%) mode change 100755 => 100644 rename Hologram/{Network/Modem/ModemMode/ModemMode.py => PPP/__init__.py} (59%) rename Hologram/{Network/Modem/ModemMode => PPP}/pppd.py (98%) rename Hologram/{Network => Utils}/Route.py (100%) rename UtilClasses/UtilClasses.py => Hologram/Utils/__init__.py (96%) delete mode 100644 ISSUE_TEMPLATE.md delete mode 100755 UtilClasses/__init__.py create mode 100644 tests/Modem/Huawei/test_E303.py create mode 100644 tests/Modem/Huawei/test_E372.py rename tests/Modem/{ => Huawei}/test_MS2131.py (97%) create mode 100644 tests/Modem/Quectel/test_BG96.py rename tests/Modem/{ => UBlox}/test_Nova.py (97%) rename tests/Modem/{ => UBlox}/test_NovaM.py (98%) rename tests/Modem/{ => UBlox}/test_NovaU201.py (98%) rename {Hologram/Network/Modem/ModemMode => tests/PPP}/MockPPP.py (81%) mode change 100755 => 100644 create mode 100644 tests/PPP/init.py rename tests/{ModemMode/test_ModemMode.py => PPP/test_IPPP.py} (73%) rename tests/{ModemMode => PPP}/test_PPP.py (92%) create mode 100644 tests/init.py diff --git a/Hologram/Api/Api.py b/Hologram/Api/Api.py index acb28e09..cfb524cb 100644 --- a/Hologram/Api/Api.py +++ b/Hologram/Api/Api.py @@ -9,7 +9,7 @@ import logging from logging import NullHandler -from Exceptions.HologramError import ApiError +from Hologram.Exceptions.HologramError import ApiError import requests HOLOGRAM_REST_API_BASEURL = 'https://dashboard.hologram.io/api/1' diff --git a/Hologram/Authentication/CSRPSKAuthentication.py b/Hologram/Authentication/CSRPSKAuthentication.py index 6bca0cd1..a38f6e7b 100644 --- a/Hologram/Authentication/CSRPSKAuthentication.py +++ b/Hologram/Authentication/CSRPSKAuthentication.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License # import json -from Exceptions.HologramError import AuthenticationError +from Hologram.Exceptions.HologramError import AuthenticationError from Hologram.Authentication.HologramAuthentication import HologramAuthentication DEVICE_KEY_LEN = 8 diff --git a/Hologram/CustomCloud.py b/Hologram/CustomCloud.py index 58eb0aea..919bcdcc 100644 --- a/Hologram/CustomCloud.py +++ b/Hologram/CustomCloud.py @@ -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.HologramError import HologramError MAX_RECEIVE_BYTES = 1024 MAX_QUEUED_CONNECTIONS = 5 diff --git a/Hologram/Event/Event.py b/Hologram/Event.py similarity index 100% rename from Hologram/Event/Event.py rename to Hologram/Event.py diff --git a/Hologram/Event/__init__.py b/Hologram/Event/__init__.py deleted file mode 100644 index 53640d77..00000000 --- a/Hologram/Event/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -__all__ = ['Event'] -from .Event import * diff --git a/Exceptions/HologramError.py b/Hologram/Exceptions/HologramError.py similarity index 100% rename from Exceptions/HologramError.py rename to Hologram/Exceptions/HologramError.py diff --git a/Exceptions/__init__.py b/Hologram/Exceptions/__init__.py similarity index 100% rename from Exceptions/__init__.py rename to Hologram/Exceptions/__init__.py diff --git a/Hologram/HologramCloud.py b/Hologram/HologramCloud.py index 6c730363..d8bc60be 100755 --- a/Hologram/HologramCloud.py +++ b/Hologram/HologramCloud.py @@ -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.HologramError import HologramError DEFAULT_SEND_MESSAGE_TIMEOUT = 5 HOLOGRAM_HOST_SEND = 'cloudsocket.hologram.io' diff --git a/Hologram/Network/Modem/DriverLoader.py b/Hologram/Modem/DriverLoader.py similarity index 100% rename from Hologram/Network/Modem/DriverLoader.py rename to Hologram/Modem/DriverLoader.py diff --git a/Hologram/Network/Modem/E303.py b/Hologram/Modem/Huawei/E303.py similarity index 96% rename from Hologram/Network/Modem/E303.py rename to Hologram/Modem/Huawei/E303.py index 2f066e9f..e1a5a612 100644 --- a/Hologram/Network/Modem/E303.py +++ b/Hologram/Modem/Huawei/E303.py @@ -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 diff --git a/Hologram/Network/Modem/E372.py b/Hologram/Modem/Huawei/E372.py similarity index 96% rename from Hologram/Network/Modem/E372.py rename to Hologram/Modem/Huawei/E372.py index cfed7a31..375c8a02 100644 --- a/Hologram/Network/Modem/E372.py +++ b/Hologram/Modem/Huawei/E372.py @@ -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 diff --git a/Hologram/Network/Modem/MS2131.py b/Hologram/Modem/Huawei/MS2131.py similarity index 96% rename from Hologram/Network/Modem/MS2131.py rename to Hologram/Modem/Huawei/MS2131.py index ecc80e28..777be28c 100644 --- a/Hologram/Network/Modem/MS2131.py +++ b/Hologram/Modem/Huawei/MS2131.py @@ -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 diff --git a/Hologram/Modem/Huawei/init.py b/Hologram/Modem/Huawei/init.py new file mode 100644 index 00000000..e69de29b diff --git a/Hologram/Network/Modem/BG96.py b/Hologram/Modem/Quectel/BG96.py similarity index 97% rename from Hologram/Network/Modem/BG96.py rename to Hologram/Modem/Quectel/BG96.py index c3424c3b..d071653c 100644 --- a/Hologram/Network/Modem/BG96.py +++ b/Hologram/Modem/Quectel/BG96.py @@ -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.HologramError import SerialError, NetworkError DEFAULT_BG96_TIMEOUT = 200 diff --git a/Hologram/Modem/Quectel/init.py b/Hologram/Modem/Quectel/init.py new file mode 100644 index 00000000..e69de29b diff --git a/Hologram/Modem/UBlox/Nova.py b/Hologram/Modem/UBlox/Nova.py new file mode 100644 index 00000000..34aed843 --- /dev/null +++ b/Hologram/Modem/UBlox/Nova.py @@ -0,0 +1,90 @@ +# Nova.py - Hologram Python SDK Nova modem interface +# +# Author: Hologram +# +# Copyright 2016 - Hologram (Konekt, Inc.) +# +# +# LICENSE: Distributed under the terms of the MIT License +# + +from Hologram.Modem import Modem +from Hologram.Utils import ModemResult +from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Event import Event + +DEFAULT_NOVA_TIMEOUT = 200 + +class Nova(Modem): + + 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) + + def disable_at_sockets_mode(self): + self._at_sockets_available = False + + def enable_at_sockets_mode(self): + self._at_sockets_available = True + + def _is_pdp_context_active(self): + if not self.is_registered(): + return False + + ok, r = self.set('+UPSND', '0,8') + if ok == ModemResult.OK: + try: + pdpstatus = int(r.lstrip('UPSND: ').split(',')[2]) + # 1: PDP active + return pdpstatus == 1 + except (IndexError, ValueError) as e: + self.logger.error(repr(e)) + return False + + def _set_up_pdp_context(self): + if self._is_pdp_context_active(): return True + self.logger.info('Setting up PDP context') + self.set('+UPSD', '0,1,\"hologram\"') + self.set('+UPSD', '0,7,\"0.0.0.0\"') + ok, _ = self.set('+UPSDA', '0,3', timeout=30) + if ok != ModemResult.OK: + self.logger.error('PDP Context setup failed') + raise NetworkError('Failed PDP context setup') + else: + self.logger.info('PDP context active') + + def enable_hex_mode(self): + self.__set_hex_mode(1) + + def disable_hex_mode(self): + self.__set_hex_mode(0) + + def __set_hex_mode(self, enable_hex_mode): + self.command('+UDCONF', '1,%d' % enable_hex_mode) + + @property + def modem_mode(self): + mode_number = None + # trim: + # +UUSBCONF: 0,"",,"0x1102" -> 0 + # +UUSBCONF: 2,"ECM",,"0x1104" -> 2 + try: + ok, res = self.read('+UUSBCONF') + if ok == ModemResult.OK: + mode_number = int(res.lstrip('+UUSBCONF: ').split(',')[0]) + except (IndexError, ValueError) as e: + self.logger.error(repr(e)) + return mode_number + + @property + def version(self): + return self._basic_command('I9') + + @property + def operator(self): + op = self._basic_set('+UDOPN','12') + if op is not None: + return op.strip('"') + return op diff --git a/Hologram/Network/Modem/NovaM.py b/Hologram/Modem/UBlox/NovaM.py similarity index 95% rename from Hologram/Network/Modem/NovaM.py rename to Hologram/Modem/UBlox/NovaM.py index b57c3a5e..c9fb7372 100644 --- a/Hologram/Network/Modem/NovaM.py +++ b/Hologram/Modem/UBlox/NovaM.py @@ -8,10 +8,10 @@ # LICENSE: Distributed under the terms of the MIT License # -from Hologram.Network.Modem.Nova import Nova +from Hologram.Modem.Nova import Nova from Hologram.Event import Event -from Exceptions.HologramError import NetworkError -from UtilClasses import ModemResult +from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Utils import ModemResult DEFAULT_NOVAM_TIMEOUT = 200 diff --git a/Hologram/Network/Modem/Nova_U201.py b/Hologram/Modem/UBlox/Nova_U201.py similarity index 96% rename from Hologram/Network/Modem/Nova_U201.py rename to Hologram/Modem/UBlox/Nova_U201.py index ad21c049..e93df9de 100644 --- a/Hologram/Network/Modem/Nova_U201.py +++ b/Hologram/Modem/UBlox/Nova_U201.py @@ -8,11 +8,11 @@ # LICENSE: Distributed under the terms of the MIT License # -from Hologram.Network.Modem.Nova import Nova -from Exceptions.HologramError import SerialError +from Hologram.Modem.Nova import Nova +from Hologram.Exceptions.HologramError import SerialError from Hologram.Event import Event -from UtilClasses import Location -from UtilClasses import ModemResult +from Hologram.Utils import Location +from Hologram.Utils import ModemResult DEFAULT_NOVA_U201_TIMEOUT = 200 diff --git a/Hologram/Modem/UBlox/init.py b/Hologram/Modem/UBlox/init.py new file mode 100644 index 00000000..e69de29b diff --git a/Hologram/Network/Modem/Modem.py b/Hologram/Modem/__init__.py similarity index 91% rename from Hologram/Network/Modem/Modem.py rename to Hologram/Modem/__init__.py index 424aaba3..613016fa 100644 --- a/Hologram/Network/Modem/Modem.py +++ b/Hologram/Modem/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Modem.py - Hologram Python SDK Modem interface # # Author: Hologram @@ -8,18 +7,19 @@ # # LICENSE: Distributed under the terms of the MIT License -from Hologram.Network.Modem import IModem -from Hologram.Network.Modem.ModemMode import PPP -from UtilClasses import ModemResult -from UtilClasses import SMS +from Hologram.Modem import IModem +from Hologram.PPP.PPP import PPP +from Hologram.Utils import ModemResult +from Hologram.Utils import SMS from Hologram.Event import Event -from Exceptions.HologramError import SerialError, HologramError, NetworkError, PPPError +from Hologram.Exceptions.HologramError import SerialError, HologramError, NetworkError, PPPError from collections import deque import binascii import datetime import logging +from logging import NullHandler import os import serial from serial.tools import list_ports @@ -28,7 +28,13 @@ DEFAULT_CHATSCRIPT_PATH = '/chatscripts/default-script' -class Modem(IModem): +# Modem error codes - this is similar to what we have in Dash system firmware. +MODEM_NO_MATCH = -3 +MODEM_ERROR = -2 +MODEM_TIMEOUT = -1 +MODEM_OK = 0 + +class Modem: DEFAULT_MODEM_RESTART_TIME = 20 DEFAULT_SERIAL_READ_SIZE = 256 @@ -57,11 +63,30 @@ class Modem(IModem): 0x2F: u'\\', } + usb_ids = [] + # module needed by modem + module = '' + # system path to write usb IDs to to force use of a driver + syspath = '' + + _error_code_description = { + + MODEM_NO_MATCH: 'Modem response doesn\'t match expected return value', + MODEM_ERROR: 'Modem error', + MODEM_TIMEOUT: 'Modem timeout', + MODEM_OK: 'Modem returned OK' + } + def __init__(self, device_name=None, baud_rate='9600', chatscript_file=None, event=Event()): - super().__init__(device_name=device_name, baud_rate=baud_rate, - event=event) + # Logging setup. + self.logger = logging.getLogger(__name__) + self.logger.addHandler(NullHandler()) + + self.event = event + self.device_name = device_name + self.baud_rate = baud_rate self.serial_port = None self.timeout = Modem.DEFAULT_SERIAL_TIMEOUT @@ -81,28 +106,28 @@ def __init__(self, device_name=None, baud_rate='9600', # This serial mode device name/port will always be equivalent to whatever the # default port is for the specific modem. - self._mode = None + self._ppp = None self.initialize_serial_interface() self.logger.info('Instantiated a %s interface with device name of %s', self.__repr__(), self.device_name) def isConnected(self): - return self._mode.isConnected() + return self._ppp.isConnected() def connect(self, timeout): - if self._mode is None: - self._mode = PPP(device_name=self.device_name, + if self._ppp is None: + self._ppp = PPP(device_name=self.device_name, all_attached_device_names=self.__detect_all_serial_ports(), baud_rate=self.baud_rate, chatscript_file=self.chatscript_file) - return self._mode.connect(timeout = timeout) + return self._ppp.connect(timeout = timeout) def disconnect(self): - if self._mode is not None: - res = self._mode.disconnect() - self._mode = None + if self._ppp is not None: + res = self._ppp.disconnect() + self._ppp = None return res else: try: @@ -694,32 +719,6 @@ def check_registered(self, cmd): def is_registered(self): pass - def _is_pdp_context_active(self): - if not self.is_registered(): - return False - - ok, r = self.set('+UPSND', '0,8') - if ok == ModemResult.OK: - try: - pdpstatus = int(r.lstrip('UPSND: ').split(',')[2]) - # 1: PDP active - return pdpstatus == 1 - except (IndexError, ValueError) as e: - self.logger.error(repr(e)) - return False - - def _set_up_pdp_context(self): - if self._is_pdp_context_active(): return True - self.logger.info('Setting up PDP context') - self.set('+UPSD', '0,1,\"hologram\"') - self.set('+UPSD', '0,7,\"0.0.0.0\"') - ok, _ = self.set('+UPSDA', '0,3', timeout=30) - if ok != ModemResult.OK: - self.logger.error('PDP Context setup failed') - raise NetworkError('Failed PDP context setup') - else: - self.logger.info('PDP context active') - def __enforce_serial_port_open(self): if not (self.serial_port and self.serial_port.isOpen()): @@ -821,13 +820,36 @@ def enable_at_sockets_mode(self): pass def enable_hex_mode(self): - self.__set_hex_mode(1) + pass def disable_hex_mode(self): - self.__set_hex_mode(0) + pass - def __set_hex_mode(self, enable_hex_mode): - self.command('+UDCONF', '1,%d' % enable_hex_mode) + def __repr__(self): + return type(self).__name__ + + # REQUIRES: A result code (int). + # EFFECTS: Returns a translated string based on the given modem result code. + def getResultString(self, result_code): + if result_code not in self._error_code_description: + return 'Unknown response code' + return self._error_code_description[result_code] + + @property + def description(self): + return self.__repr__() + + @property + def operator(self): + raise NotImplementedError('Must instantiate a Modem type') + + @property + def device_name(self): + return self._device_name + + @device_name.setter + def device_name(self, device_name): + self._device_name = device_name @property def serial_port(self): @@ -857,39 +879,18 @@ def modem_id(self): def iccid(self): return self._basic_command('+CCID') - @property - def operator(self): - op = self._basic_set('+UDOPN','12') - if op is not None: - return op.strip('"') - return op - @property def location(self): raise NotImplementedError('This modem does not support this property') @property - def mode(self): - return self._mode + def ppp(self): + return self._ppp @property def at_sockets_available(self): return self._at_sockets_available - @property - def modem_mode(self): - mode_number = None - # trim: - # +UUSBCONF: 0,"",,"0x1102" -> 0 - # +UUSBCONF: 2,"ECM",,"0x1104" -> 2 - try: - ok, res = self.read('+UUSBCONF') - if ok == ModemResult.OK: - mode_number = int(res.lstrip('+UUSBCONF: ').split(',')[0]) - except (IndexError, ValueError) as e: - self.logger.error(repr(e)) - return mode_number - @modem_mode.setter def modem_mode(self, mode): self.set('+UUSBCONF', str(mode)) @@ -901,15 +902,15 @@ def modem_mode(self, mode): @property def localIPAddress(self): - if self._mode: - return self._mode.localIPAddress + if self._ppp: + return self._ppp.localIPAddress else: return None @property def remoteIPAddress(self): - if self._mode: - return self._mode.remoteIPAddress + if self._ppp: + return self._ppp.remoteIPAddress else: return None diff --git a/Hologram/Network/Modem/chatscripts/__init__.py b/Hologram/Modem/chatscripts/__init__.py similarity index 100% rename from Hologram/Network/Modem/chatscripts/__init__.py rename to Hologram/Modem/chatscripts/__init__.py diff --git a/Hologram/Network/Modem/chatscripts/default-script b/Hologram/Modem/chatscripts/default-script old mode 100755 new mode 100644 similarity index 100% rename from Hologram/Network/Modem/chatscripts/default-script rename to Hologram/Modem/chatscripts/default-script diff --git a/Hologram/Network/Cellular.py b/Hologram/Network.py similarity index 93% rename from Hologram/Network/Cellular.py rename to Hologram/Network.py index 928c69ff..a037a883 100644 --- a/Hologram/Network/Cellular.py +++ b/Hologram/Network.py @@ -1,6 +1,6 @@ -# Cellular.py - Hologram Python SDK Cellular interface -# Author: Hologram +# Network.py - Hologram Python SDK Network interface # +# Author: Hologram # # Copyright 2016 - Hologram (Konekt, Inc.) # @@ -9,12 +9,19 @@ # from Hologram.Event import Event -from Exceptions.HologramError import NetworkError -from Hologram.Network.Route import Route -from Hologram.Network.Modem import Modem, E303, MS2131, E372, BG96, Nova_U201, NovaM, DriverLoader -from Hologram.Network import Network, NetworkScope +from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Utils.Route import Route +from Hologram.Modem import Modem, E303, MS2131, E372, BG96, Nova_U201, NovaM, DriverLoader +import logging import time +from logging import NullHandler from serial.tools import list_ports +from enum import Enum + + +class NetworkScope(Enum): + SYSTEM = 1 + HOLOGRAM = 2 # Cellular return codes. CLOUD_DISCONNECTED = 0 @@ -25,7 +32,7 @@ DEFAULT_CELLULAR_TIMEOUT = 200 # slightly more than 3 mins -class Cellular(Network): +class Network: _modemHandlers = { 'e303': E303.E303, @@ -38,7 +45,11 @@ class Cellular(Network): } def __init__(self, event=Event()): - super().__init__(event=event) + self.event = event + # Logging setup. + self.logger = logging.getLogger(__name__) + self.logger.addHandler(NullHandler()) + self.scope = NetworkScope.SYSTEM self._connection_status = CLOUD_DISCONNECTED self._modem = None self._route = Route() @@ -81,7 +92,6 @@ def connect(self, timeout = DEFAULT_CELLULAR_TIMEOUT): self.__configure_routing() self._connection_status = CLOUD_CONNECTED self.event.broadcast('cellular.connected') - super().connect() else: self.logger.info('Failed to connect to cell network') @@ -96,7 +106,6 @@ def disconnect(self): self.enable_at_sockets_mode() self._connection_status = CLOUD_DISCONNECTED self.event.broadcast('cellular.disconnected') - super().disconnect() else: self.logger.info('Failed to disconnect from cell network') @@ -285,4 +294,4 @@ def location(self): @property def at_sockets_available(self): - return self.modem.at_sockets_available + return self.modem.at_sockets_available \ No newline at end of file diff --git a/Hologram/Network/BLE.py b/Hologram/Network/BLE.py deleted file mode 100644 index 44e73f57..00000000 --- a/Hologram/Network/BLE.py +++ /dev/null @@ -1,22 +0,0 @@ -from Hologram.Event import Event -from Hologram.Network import Network - -class BLE(Network): - - def __init__(self): - self.event = Event() - super().__init__() - - def connect(self): - self.event.broadcast('ble.connected') - return True - - def disconnect(self): - self.event.broadcast('ble.disconnected') - return True - - def getConnectionStatus(self): - raise Exception('BLE mode doesn\'t support this call yet') - - def reconnect(self): - return True diff --git a/Hologram/Network/Ethernet.py b/Hologram/Network/Ethernet.py deleted file mode 100644 index 4be4d49a..00000000 --- a/Hologram/Network/Ethernet.py +++ /dev/null @@ -1,39 +0,0 @@ -from Hologram.Network import Network -from Hologram.Event import Event -import time -import os - -class Ethernet(Network): - - def __init__(self, interfaceName = 'eth0'): - self.interfaceName = interfaceName - # TODO(zheng): change to ethernet library - # self.ethernet = Wireless(interfaceName) - super().__init__() - - def getBitRate(self): - # bitrate = self.ethernet.wireless_info.getBitrate() - # return "Bit Rate :%s" % self.ethernet.getBitrate() - return '' - - def disconnect(self): - os.system("ifconfig " + self.interfaceName + " down") - self.event.broadcast('ethernet.disconnected') - super().disconnect() - - def connect(self): - os.system("ifconfig " + self.interfaceName + " up") - self.event.broadcast('ethernet.connected') - super().connect() - - def isConnected(self): - return True - - def getConnectionStatus(self): - raise Exception('Ethernet mode doesn\'t support this call') - - def getSignalStrength(self): - raise Exception('Ethernet mode doesn\'t support this call') - - def getAvgSignalStrength(self): - raise Exception('Ethernet mode doesn\'t support this call') diff --git a/Hologram/Network/Modem/IModem.py b/Hologram/Network/Modem/IModem.py deleted file mode 100644 index 654dd751..00000000 --- a/Hologram/Network/Modem/IModem.py +++ /dev/null @@ -1,126 +0,0 @@ -# Modem.py - Hologram Python SDK Modem interface -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License - -import logging -from logging import NullHandler -from Hologram.Event import Event - -# Modem error codes - this is similar to what we have in Dash system firmware. -MODEM_NO_MATCH = -3 -MODEM_ERROR = -2 -MODEM_TIMEOUT = -1 -MODEM_OK = 0 - -class IModem: - - usb_ids = [] - # module needed by modem - module = '' - # system path to write usb IDs to to force use of a driver - syspath = '' - - _error_code_description = { - - MODEM_NO_MATCH: 'Modem response doesn\'t match expected return value', - MODEM_ERROR: 'Modem error', - MODEM_TIMEOUT: 'Modem timeout', - MODEM_OK: 'Modem returned OK' - } - - def __init__(self, device_name='/dev/ttyUSB0', baud_rate='9600', event=Event()): - # Logging setup. - self.logger = logging.getLogger(__name__) - self.logger.addHandler(NullHandler()) - - self.event = event - self.device_name = device_name - self.baud_rate = baud_rate - - def __repr__(self): - return type(self).__name__ - - # REQUIRES: A result code (int). - # EFFECTS: Returns a translated string based on the given modem result code. - def getResultString(self, result_code): - if result_code not in self._error_code_description: - return 'Unknown response code' - return self._error_code_description[result_code] - - def isConnected(self): - raise NotImplementedError('Must instantiate a Modem type') - - def connect(self): - raise NotImplementedError('Must instantiate a Modem type') - - def disconnect(self): - raise NotImplementedError('Must instantiate a Modem type') - - def reset(self): - raise NotImplementedError('Must instantiate a Modem type') - - def radio_power(self, power_mode): - raise NotImplementedError('Must instantiate a Modem type') - - def enableSMS(self): - raise NotImplementedError('Must instantiate a Modem type') - - def disableSMS(self): - raise NotImplementedError('Must instantiate a Modem type') - - def popReceivedSMS(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def description(self): - return self.__repr__() - - @property - def localIPAddress(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def remoteIPAddress(self): - raise NotImplementedError('Must instantiate a Modem type') - - # EFFECTS: Returns the Received Signal Strength Indication (RSSI) value of the modem - @property - def signal_strength(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def modem_id(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def imsi(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def iccid(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def location(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def operator(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def mode(self): - raise NotImplementedError('Must instantiate a Modem type') - - @property - def device_name(self): - return self._device_name - - @device_name.setter - def device_name(self, device_name): - self._device_name = device_name diff --git a/Hologram/Network/Modem/MockModem.py b/Hologram/Network/Modem/MockModem.py deleted file mode 100644 index 75028bae..00000000 --- a/Hologram/Network/Modem/MockModem.py +++ /dev/null @@ -1,23 +0,0 @@ -# MockModem.py - Hologram Python SDK mock modem interface -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License -# - -from Hologram.Network.Modem import IModem - -E303_DEVICE_NAME = '/dev/ttyUSB0' -DEFAULT_E303_TIMEOUT = 200 - -class MockModem(IModem): - - def __init__(self, device_name=E303_DEVICE_NAME, baud_rate='9600', - chatscript_file=None): - super().__init__(device_name=device_name, baud_rate=baud_rate) - - def _get_attached_devices(self): - return '/dev/test1, /dev/test2, /dev/ttyACM0' diff --git a/Hologram/Network/Modem/ModemMode/IPPP.py b/Hologram/Network/Modem/ModemMode/IPPP.py deleted file mode 100755 index 1560fa06..00000000 --- a/Hologram/Network/Modem/ModemMode/IPPP.py +++ /dev/null @@ -1,34 +0,0 @@ -# IPPP.py - Hologram Python SDK Modem PPP interface -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License -# -from Hologram.Network.Modem.ModemMode.ModemMode import ModemMode - -class IPPP(ModemMode): - - def __init__(self, device_name='/dev/ttyUSB0', baud_rate='9600', - chatscript_file=None): - - super().__init__(device_name=device_name, baud_rate=baud_rate) - - self.chatscript_file = chatscript_file - - if self.chatscript_file is None: - raise Exception('Must specify chatscript file') - - @property - def connect_script(self): - return '/usr/sbin/chat -v -f ' + self.chatscript_file - - @property - def chatscript_file(self): - return self._chatscript_file - - @chatscript_file.setter - def chatscript_file(self, chatscript_file): - self._chatscript_file = chatscript_file diff --git a/Hologram/Network/Modem/ModemMode/__init__.py b/Hologram/Network/Modem/ModemMode/__init__.py deleted file mode 100644 index e7432f19..00000000 --- a/Hologram/Network/Modem/ModemMode/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -__all__ = ['ModemMode', 'IPPP', 'PPP'] -from .PPP import PPP -from .ModemMode import ModemMode -from .IPPP import IPPP \ No newline at end of file diff --git a/Hologram/Network/Modem/Nova.py b/Hologram/Network/Modem/Nova.py deleted file mode 100644 index c3ddd031..00000000 --- a/Hologram/Network/Modem/Nova.py +++ /dev/null @@ -1,33 +0,0 @@ -# Nova.py - Hologram Python SDK Nova modem interface -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License -# - -from Hologram.Network.Modem import Modem -from Hologram.Event import Event - -DEFAULT_NOVA_TIMEOUT = 200 - -class Nova(Modem): - - 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) - - def disable_at_sockets_mode(self): - self._at_sockets_available = False - - def enable_at_sockets_mode(self): - self._at_sockets_available = True - - @property - def version(self): - return self._basic_command('I9') - diff --git a/Hologram/Network/Modem/__init__.py b/Hologram/Network/Modem/__init__.py deleted file mode 100644 index fe44d41c..00000000 --- a/Hologram/Network/Modem/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -__all__ = ['Modem', 'MockModem', 'MS2131', 'Nova', 'E303', 'E372'] - -from .IModem import IModem -from .Modem import Modem diff --git a/Hologram/Network/Network.py b/Hologram/Network/Network.py deleted file mode 100644 index 9f99feea..00000000 --- a/Hologram/Network/Network.py +++ /dev/null @@ -1,62 +0,0 @@ -# Network.py - Hologram Python SDK Network interface -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License -# - -from Hologram.Event import Event -import logging -from logging import NullHandler -from enum import Enum - - -class NetworkScope(Enum): - SYSTEM = 1 - HOLOGRAM = 2 - - -class Network: - - def __repr__(self): - return type(self).__name__ - - def __init__(self, event=Event()): - self.event = event - # Logging setup. - self.logger = logging.getLogger(__name__) - self.logger.addHandler(NullHandler()) - self.scope = NetworkScope.SYSTEM - - def connect(self): - self.event.broadcast('network.connected') - return True - - def disconnect(self): - self.event.broadcast('network.disconnected') - - def reconnect(self): - raise NotImplementedError('Must instantiate a defined Network type') - - def getConnectionStatus(self): - raise NotImplementedError('Must instantiate a defined Network type') - - def getSignalStrength(self): - raise NotImplementedError('Must instantiate a defined Network type') - - def getAvgSignalStrength(self): - raise NotImplementedError('Must instantiate a defined Network type') - - def is_connected(self): - return False - - @property - def interfaceName(self): - return self._interfaceName - - @interfaceName.setter - def interfaceName(self, name): - self._interfaceName = name diff --git a/Hologram/Network/NetworkManager.py b/Hologram/Network/NetworkManager.py deleted file mode 100644 index e0866471..00000000 --- a/Hologram/Network/NetworkManager.py +++ /dev/null @@ -1,84 +0,0 @@ -# NetworkManager.py - Hologram Python SDK Network manager interface -# This handles the network/connectivity interface for Hologram SDK. -# -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# -# LICENSE: Distributed under the terms of the MIT License -# - -from Hologram.Network import Wifi, Ethernet, BLE, Cellular -from Exceptions.HologramError import NetworkError -import logging -from logging import NullHandler -import os - -DEFAULT_NETWORK_TIMEOUT = 200 - -class NetworkManager: - - _networkHandlers = { - 'wifi' : Wifi.Wifi, - 'cellular': Cellular.Cellular, - 'ble' : BLE.BLE, - 'ethernet' : Ethernet.Ethernet, - } - - def __init__(self, event, network): - - # Logging setup. - self.logger = logging.getLogger(__name__) - self.logger.addHandler(NullHandler()) - - self.event = event - self.networkActive = False - self.network = network - - # EFFECTS: Event handler function that sets the network disconnect flag. - def networkDisconnected(self): - self.networkActive = False - - def networkConnected(self): - self.networkActive = True - - def listAvailableInterfaces(self): - return self._networkHandlers.keys() - - @property - def network(self): - return self._network - - @network.setter - def network(self, network, modem=None): - if not network: # non-network mode - self.networkConnected() - self._network = None - elif network not in self._networkHandlers: - raise NetworkError('Invalid network type: %s' % network) - else: - self.__enforce_network_privileges() - self._network = self._networkHandlers[network](self.event) - if network == 'cellular': - if modem is not None: - self._network.modem = modem - else: - 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() - - - def __repr__(self): - if not self.network: - return 'Network Agnostic Mode' - - return type(self.network).__name__ - - def __enforce_network_privileges(self): - - if os.geteuid() != 0: - raise RuntimeError('You need to have root privileges to use this interface. Please try again, this time using sudo.') diff --git a/Hologram/Network/Wifi.py b/Hologram/Network/Wifi.py deleted file mode 100644 index d35577a9..00000000 --- a/Hologram/Network/Wifi.py +++ /dev/null @@ -1,67 +0,0 @@ -from Hologram.Network import Network -from Hologram.Event import Event -import time -import os - -class Wifi(Network): - - def __init__(self, interfaceName = 'wlan0'): - self.interfaceName = interfaceName - # self.wifi = Wireless(interfaceName) - super().__init__() - self.event.broadcast('wifi.connected') - - def getSSID(self): - return '' #self.wifi.getEssid() - - def getMode(self): - return '' # return self.wifi.getMode() - - def getWirelessName(self): - return '' # return self.wifi.getWirelessName() - - def getBitRate(self): - # bitrate = self.wifi.wireless_info.getBitrate() - # return "Bit Rate :%s" % self.wifi.getBitrate() - return '' - - def getAvgSignalStrength(self): - # mq = self.wifi.getQualityAvg() - # return "quality: " + str(mq.quality) + " signal: " + str(mq.siglevel) \ - # + " noise: " + str(mq.nlevel) - return '' - - def getMaxSignalStrength(self): - # mq = self.wifi.getQualityMax() - # return "quality: " + str(mq.quality) + " signal: " + str(mq.siglevel) \ - # + " noise: " + str(mq.nlevel) - return '' - - def disconnect(self): - os.system("ifconfig " + self.interfaceName + " down") - self.event.broadcast('wifi.disconnected') - super().disconnect() - - def connect(self): - os.system("ifconfig " + self.interfaceName + " up") - self.event.broadcast('wifi.connected') - super().connect() - - # EFFECTS: Returns the AP address. - def getAPAddress(self): - self.disconnect() - time.sleep(5) - self.connect() - # return self.wifi.getAPaddr() - - def getConnectionStatus(self): - raise Exception('WiFi mode doesn\'t support this call yet') - - def setAPAddress(self, ap): - try: - self.wifi.setAPaddr(ap) - except: - raise Exception('Unable to set AP address to ' + str(ap)) - - def isConnected(self): - return True diff --git a/Hologram/Network/__init__.py b/Hologram/Network/__init__.py deleted file mode 100644 index 3a3171c1..00000000 --- a/Hologram/Network/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -__all__ = ['Cellular', 'BLE', 'Wifi', 'Ethernet', 'Network'] - -from .Network import Network, NetworkScope diff --git a/Hologram/Network/Modem/ModemMode/PPP.py b/Hologram/PPP/PPP.py old mode 100755 new mode 100644 similarity index 94% rename from Hologram/Network/Modem/ModemMode/PPP.py rename to Hologram/PPP/PPP.py index 28d629b9..373f4ad6 --- a/Hologram/Network/Modem/ModemMode/PPP.py +++ b/Hologram/PPP/PPP.py @@ -8,10 +8,10 @@ # LICENSE: Distributed under the terms of the MIT License # import psutil -from Hologram.Network.Modem.ModemMode.pppd import PPPConnection -from Hologram.Network.Modem.ModemMode.IPPP import IPPP -from Hologram.Network.Route import Route -from Exceptions.HologramError import PPPError +from Hologram.PPP.pppd import PPPConnection +from Hologram.PPP import IPPP +from Hologram.Util.Route import Route +from Hologram.Exceptions.HologramError import PPPError DEFAULT_PPP_TIMEOUT = 200 DEFAULT_PPP_INTERFACE = 'ppp0' diff --git a/Hologram/Network/Modem/ModemMode/ModemMode.py b/Hologram/PPP/__init__.py similarity index 59% rename from Hologram/Network/Modem/ModemMode/ModemMode.py rename to Hologram/PPP/__init__.py index 7ce6f2b9..6b2db24a 100644 --- a/Hologram/Network/Modem/ModemMode/ModemMode.py +++ b/Hologram/PPP/__init__.py @@ -1,4 +1,4 @@ -# ModemMode.py - Hologram Python SDK modem mode interface +# IPPP.py - Hologram Python SDK Modem PPP interface # # Author: Hologram # @@ -11,12 +11,10 @@ from logging import NullHandler from Hologram.Event import Event -class ModemMode: +class IPPP: - def __repr__(self): - return type(self).__name__ - - def __init__(self, device_name='/dev/ttyUSB0', baud_rate='9600', event=Event()): + def __init__(self, device_name='/dev/ttyUSB0', baud_rate='9600', + chatscript_file=None, event=Event()): # Logging setup. self.logger = logging.getLogger(__name__) @@ -26,6 +24,11 @@ def __init__(self, device_name='/dev/ttyUSB0', baud_rate='9600', event=Event()): self.device_name = device_name self.baud_rate = baud_rate + self.chatscript_file = chatscript_file + + if self.chatscript_file is None: + raise Exception('Must specify chatscript file') + @property def device_name(self): return self._device_name @@ -41,3 +44,15 @@ def baud_rate(self): @baud_rate.setter def baud_rate(self, baud_rate): self._baud_rate = baud_rate + + @property + def connect_script(self): + return '/usr/sbin/chat -v -f ' + self.chatscript_file + + @property + def chatscript_file(self): + return self._chatscript_file + + @chatscript_file.setter + def chatscript_file(self, chatscript_file): + self._chatscript_file = chatscript_file diff --git a/Hologram/Network/Modem/ModemMode/pppd.py b/Hologram/PPP/pppd.py similarity index 98% rename from Hologram/Network/Modem/ModemMode/pppd.py rename to Hologram/PPP/pppd.py index 5c3323ee..e0793dcb 100644 --- a/Hologram/Network/Modem/ModemMode/pppd.py +++ b/Hologram/PPP/pppd.py @@ -17,7 +17,7 @@ import threading import errno from subprocess import Popen, PIPE, STDOUT -from Exceptions.HologramError import PPPError, PPPConnectionError +from Hologram.Exceptions.HologramError import PPPError, PPPConnectionError __version__ = '1.0.3' diff --git a/Hologram/Network/Route.py b/Hologram/Utils/Route.py similarity index 100% rename from Hologram/Network/Route.py rename to Hologram/Utils/Route.py diff --git a/UtilClasses/UtilClasses.py b/Hologram/Utils/__init__.py similarity index 96% rename from UtilClasses/UtilClasses.py rename to Hologram/Utils/__init__.py index 3c05c90e..eefe3a18 100644 --- a/UtilClasses/UtilClasses.py +++ b/Hologram/Utils/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# UtilClasses.py - Hologram Python SDK Util classes +# utils.py - Hologram Python SDK Util classes and functions # # Author: Hologram # diff --git a/Hologram/__init__.py b/Hologram/__init__.py index 57e9c0e6..faee78b9 100644 --- a/Hologram/__init__.py +++ b/Hologram/__init__.py @@ -1,2 +1 @@ from Hologram import * -from Hologram.Event import * diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index e3d6bc73..00000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ -If you run into SDK issues, please go [here](https://community.hologram.io/c/hardware/sdk) for help and support: - -You should open a GitHub issue only if it is a bug or a feature request. - ------------------------- - - -### Describe the problem - - -### Expected behavior -Please describe what you think the program should be doing here. - - -### Actual behavior -Please provide any useful debug logs/output here. This will help us diagnose -problems that you might have. Full stack traces can be extremely helpful here. - - -### Steps to reproduce the behavior -Please provide the exact command(s) to reproduce the error. If it's non-deterministic, -try your best to describe your observations that might help us troubleshoot the error. - -### System information -- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: -- **Python SDK installed via PyPI or GitHub**: -- **SDK version (use command below)**: -- **Python version**: -- **Hardware (modem) model**: - -We will be adding an environment capture script soon for your convenience. - -You can obtain the Python SDK version with: -`hologram version` diff --git a/UtilClasses/__init__.py b/UtilClasses/__init__.py deleted file mode 100755 index 064669d8..00000000 --- a/UtilClasses/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -__all__ = ['UtilClasses'] -from .UtilClasses import Location, ModemResult, SMS, RWLock diff --git a/scripts/hologram b/scripts/hologram index 9f1b5b54..92e32682 100755 --- a/scripts/hologram +++ b/scripts/hologram @@ -14,7 +14,7 @@ from argparse import RawTextHelpFormatter import logging import sys from Hologram.CustomCloud import CustomCloud -from Exceptions.HologramError import HologramError +from Hologram.Exceptions.HologramError import HologramError from scripts.hologram_send import parse_hologram_send_args from scripts.hologram_send import run_hologram_send diff --git a/scripts/hologram_activate.py b/scripts/hologram_activate.py index de76e69f..de7723d3 100644 --- a/scripts/hologram_activate.py +++ b/scripts/hologram_activate.py @@ -17,7 +17,7 @@ from Hologram.HologramCloud import HologramCloud from Hologram.Api import Api -from Exceptions.HologramError import HologramError +from Hologram.Exceptions.HologramError import HologramError from .hologram_util import VAction CHECK_LIVE_SIM_STATE_MAX_TIMEOUT = 120 # 2 mins for max timeout diff --git a/scripts/hologram_modem.py b/scripts/hologram_modem.py index f64c54ab..1287c5a1 100644 --- a/scripts/hologram_modem.py +++ b/scripts/hologram_modem.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License from Hologram.CustomCloud import CustomCloud -from Exceptions.HologramError import HologramError +from Hologram.Exceptions.HologramError import HologramError from .hologram_util import handle_timeout from .hologram_util import VAction import json diff --git a/scripts/hologram_network.py b/scripts/hologram_network.py index 6eec9e3e..45447b11 100644 --- a/scripts/hologram_network.py +++ b/scripts/hologram_network.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License from Hologram.CustomCloud import CustomCloud -from Exceptions.HologramError import HologramError +from Hologram.Exceptions.HologramError import HologramError from .hologram_util import VAction import psutil diff --git a/scripts/hologram_send.py b/scripts/hologram_send.py index 0e1628ab..5c328e34 100644 --- a/scripts/hologram_send.py +++ b/scripts/hologram_send.py @@ -12,7 +12,7 @@ from Hologram.CustomCloud import CustomCloud from Hologram.HologramCloud import HologramCloud -from Exceptions.HologramError import HologramError +from Hologram.Exceptions.HologramError import HologramError from .hologram_util import VAction import argparse diff --git a/tests/Authentication/test_CSRPSKAuthentication.py b/tests/Authentication/test_CSRPSKAuthentication.py index 9f71a878..8db31ecf 100644 --- a/tests/Authentication/test_CSRPSKAuthentication.py +++ b/tests/Authentication/test_CSRPSKAuthentication.py @@ -40,10 +40,3 @@ def test_build_payload_string_with_empty_modem_type_and_id(self): message = 'test with empty modem_type and modem_id' assert b"{\"k\": \"12345678\", \"m\": \"\\u0001agnostic-None\", \"d\": \"test with empty modem_type and modem_id\"}\r\r" \ == auth.buildPayloadString(message, modem_type=None) - - def test_invalid_device_key_length(self): - credentials = {'devicekey': '12345678'} - auth = CSRPSKAuthentication(credentials) - auth.credentials['devicekey'] = '12345' - with pytest.raises(Exception, match = 'Device key must be 8 characters long'): - auth.buildPayloadString('test invalid device key') diff --git a/tests/Modem/Huawei/test_E303.py b/tests/Modem/Huawei/test_E303.py new file mode 100644 index 00000000..915d5d3d --- /dev/null +++ b/tests/Modem/Huawei/test_E303.py @@ -0,0 +1,67 @@ +# Author: Hologram +# +# Copyright 2016 - Hologram (Konekt, Inc.) +# +# LICENSE: Distributed under the terms of the MIT License +# +# test_E303.py - This file implements unit tests for the E303 modem interface. + +from mock import patch +import pytest +import sys + +from Hologram.Modem.Huawei.E303 import E303 + +sys.path.append(".") +sys.path.append("..") +sys.path.append("../..") + +def mock_write(e303, message): + return True + +def mock_read(e303): + return True + +def mock_readline(e303, timeout=None, hide=False): + return '' + +def mock_open_serial_port(e303, device_name=None): + return True + +def mock_close_serial_port(e303): + return True + +def mock_detect_usable_serial_port(e303, stop_on_first=True): + return '/dev/ttyUSB0' + +@pytest.fixture +def no_serial_port(monkeypatch): + monkeypatch.setattr(E303, '_read_from_serial_port', mock_read) + monkeypatch.setattr(E303, '_readline_from_serial_port', mock_readline) + monkeypatch.setattr(E303, '_write_to_serial_port_and_flush', mock_write) + monkeypatch.setattr(E303, 'openSerialPort', mock_open_serial_port) + monkeypatch.setattr(E303, 'closeSerialPort', mock_close_serial_port) + monkeypatch.setattr(E303, 'detect_usable_serial_port', mock_detect_usable_serial_port) + +def test_init_e303_no_args(no_serial_port): + modem = E303() + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file.endswith('/chatscripts/default-script')) + assert(modem._at_sockets_available == False) + +def test_init_e303_chatscriptfileoverride(no_serial_port): + modem = E303(chatscript_file='test-chatscript') + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file == 'test-chatscript') + +@patch.object(E303, 'command') +def test_disable_at_sockets_mode_e303(mock_command, no_serial_port): + modem = E303() + + mock_command.return_value = [] + mock_command.reset_mock() + modem.disable_at_sockets_mode() + # The disable_at_sockets_mode() call should not do anything. + mock_command.assert_not_called() diff --git a/tests/Modem/Huawei/test_E372.py b/tests/Modem/Huawei/test_E372.py new file mode 100644 index 00000000..fdda6253 --- /dev/null +++ b/tests/Modem/Huawei/test_E372.py @@ -0,0 +1,67 @@ +# Author: Hologram +# +# Copyright 2016 - Hologram (Konekt, Inc.) +# +# LICENSE: Distributed under the terms of the MIT License +# +# test_E372.py - This file implements unit tests for the E372 modem interface. + +from mock import patch +import pytest +import sys + +from Hologram.Modem.Huawei.E372 import E372 + +sys.path.append(".") +sys.path.append("..") +sys.path.append("../..") + +def mock_write(e372, message): + return True + +def mock_read(e372): + return True + +def mock_readline(e372, timeout=None, hide=False): + return '' + +def mock_open_serial_port(e372, device_name=None): + return True + +def mock_close_serial_port(e372): + return True + +def mock_detect_usable_serial_port(e372, stop_on_first=True): + return '/dev/ttyUSB0' + +@pytest.fixture +def no_serial_port(monkeypatch): + monkeypatch.setattr(E372, '_read_from_serial_port', mock_read) + monkeypatch.setattr(E372, '_readline_from_serial_port', mock_readline) + monkeypatch.setattr(E372, '_write_to_serial_port_and_flush', mock_write) + monkeypatch.setattr(E372, 'openSerialPort', mock_open_serial_port) + monkeypatch.setattr(E372, 'closeSerialPort', mock_close_serial_port) + monkeypatch.setattr(E372, 'detect_usable_serial_port', mock_detect_usable_serial_port) + +def test_init_e372_no_args(no_serial_port): + modem = E372() + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file.endswith('/chatscripts/default-script')) + assert(modem._at_sockets_available == False) + +def test_init_e372_chatscriptfileoverride(no_serial_port): + modem = E372(chatscript_file='test-chatscript') + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file == 'test-chatscript') + +@patch.object(E372, 'command') +def test_disable_at_sockets_mode_e372(mock_command, no_serial_port): + modem = E372() + + mock_command.return_value = [] + mock_command.reset_mock() + modem.disable_at_sockets_mode() + # The disable_at_sockets_mode() call should not do anything. + mock_command.assert_not_called() diff --git a/tests/Modem/test_MS2131.py b/tests/Modem/Huawei/test_MS2131.py similarity index 97% rename from tests/Modem/test_MS2131.py rename to tests/Modem/Huawei/test_MS2131.py index 10a18527..9fa9ae5c 100644 --- a/tests/Modem/test_MS2131.py +++ b/tests/Modem/Huawei/test_MS2131.py @@ -10,7 +10,7 @@ import pytest import sys -from Hologram.Network.Modem.MS2131 import MS2131 +from Hologram.Modem.Huawei.MS2131 import MS2131 sys.path.append(".") sys.path.append("..") diff --git a/tests/Modem/Quectel/test_BG96.py b/tests/Modem/Quectel/test_BG96.py new file mode 100644 index 00000000..23981442 --- /dev/null +++ b/tests/Modem/Quectel/test_BG96.py @@ -0,0 +1,67 @@ +# Author: Hologram +# +# Copyright 2016 - Hologram (Konekt, Inc.) +# +# LICENSE: Distributed under the terms of the MIT License +# +# test_BG96.py - This file implements unit tests for the BG96 modem interface. + +from mock import patch +import pytest +import sys + +from Hologram.Modem.Quectel.BG96 import BG96 + +sys.path.append(".") +sys.path.append("..") +sys.path.append("../..") + +def mock_write(bg96, message): + return True + +def mock_read(bg96): + return True + +def mock_readline(bg96, timeout=None, hide=False): + return '' + +def mock_open_serial_port(bg96, device_name=None): + return True + +def mock_close_serial_port(bg96): + return True + +def mock_detect_usable_serial_port(bg96, stop_on_first=True): + return '/dev/ttyUSB0' + +@pytest.fixture +def no_serial_port(monkeypatch): + monkeypatch.setattr(BG96, '_read_from_serial_port', mock_read) + monkeypatch.setattr(BG96, '_readline_from_serial_port', mock_readline) + monkeypatch.setattr(BG96, '_write_to_serial_port_and_flush', mock_write) + monkeypatch.setattr(BG96, 'openSerialPort', mock_open_serial_port) + monkeypatch.setattr(BG96, 'closeSerialPort', mock_close_serial_port) + monkeypatch.setattr(BG96, 'detect_usable_serial_port', mock_detect_usable_serial_port) + +def test_init_bg96_no_args(no_serial_port): + modem = BG96() + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file.endswith('/chatscripts/default-script')) + assert(modem._at_sockets_available == False) + +def test_init_bg96_chatscriptfileoverride(no_serial_port): + modem = BG96(chatscript_file='test-chatscript') + assert(modem.timeout == 1) + assert(modem.socket_identifier == 0) + assert(modem.chatscript_file == 'test-chatscript') + +@patch.object(BG96, 'command') +def test_disable_at_sockets_mode_bg96(mock_command, no_serial_port): + modem = BG96() + + mock_command.return_value = [] + mock_command.reset_mock() + modem.disable_at_sockets_mode() + # The disable_at_sockets_mode() call should not do anything. + mock_command.assert_not_called() diff --git a/tests/Modem/test_Nova.py b/tests/Modem/UBlox/test_Nova.py similarity index 97% rename from tests/Modem/test_Nova.py rename to tests/Modem/UBlox/test_Nova.py index 92cacc1a..5fced4ba 100644 --- a/tests/Modem/test_Nova.py +++ b/tests/Modem/UBlox/test_Nova.py @@ -9,7 +9,7 @@ import pytest import sys -from Hologram.Network.Modem.Nova import Nova +from Hologram.Modem.UBlox.Nova import Nova sys.path.append(".") sys.path.append("..") diff --git a/tests/Modem/test_NovaM.py b/tests/Modem/UBlox/test_NovaM.py similarity index 98% rename from tests/Modem/test_NovaM.py rename to tests/Modem/UBlox/test_NovaM.py index 41215325..5b16ba4b 100644 --- a/tests/Modem/test_NovaM.py +++ b/tests/Modem/UBlox/test_NovaM.py @@ -10,7 +10,7 @@ import pytest import sys -from Hologram.Network.Modem.NovaM import NovaM +from Hologram.Modem.UBlox.NovaM import NovaM sys.path.append(".") sys.path.append("..") diff --git a/tests/Modem/test_NovaU201.py b/tests/Modem/UBlox/test_NovaU201.py similarity index 98% rename from tests/Modem/test_NovaU201.py rename to tests/Modem/UBlox/test_NovaU201.py index f3367462..37e8aa33 100644 --- a/tests/Modem/test_NovaU201.py +++ b/tests/Modem/UBlox/test_NovaU201.py @@ -10,7 +10,7 @@ import pytest import sys -from Hologram.Network.Modem.Nova_U201 import Nova_U201 +from Hologram.Modem.UBlox.Nova_U201 import Nova_U201 sys.path.append(".") sys.path.append("..") diff --git a/tests/Modem/test_Modem.py b/tests/Modem/test_Modem.py index cbf71f40..7b1b4fac 100644 --- a/tests/Modem/test_Modem.py +++ b/tests/Modem/test_Modem.py @@ -13,9 +13,9 @@ sys.path.append(".") sys.path.append("..") sys.path.append("../..") -from Exceptions.HologramError import SerialError -from Hologram.Network.Modem import Modem -from UtilClasses import ModemResult +from Hologram.Exceptions.HologramError import SerialError +from Hologram.Modem import Modem +from Hologram.Utils import ModemResult def mock_write(modem, message): return True diff --git a/Hologram/Network/Modem/ModemMode/MockPPP.py b/tests/PPP/MockPPP.py old mode 100755 new mode 100644 similarity index 81% rename from Hologram/Network/Modem/ModemMode/MockPPP.py rename to tests/PPP/MockPPP.py index 23af8c1f..cba3d076 --- a/Hologram/Network/Modem/ModemMode/MockPPP.py +++ b/tests/PPP/MockPPP.py @@ -7,7 +7,13 @@ # # LICENSE: Distributed under the terms of the MIT License # -from Hologram.Network.Modem.ModemMode.IPPP import IPPP +import sys +from datetime import datetime + +sys.path.append(".") +sys.path.append("..") +sys.path.append("../..") +from Hologram.PPP import IPPP class MockPPP(IPPP): diff --git a/tests/PPP/init.py b/tests/PPP/init.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/ModemMode/test_ModemMode.py b/tests/PPP/test_IPPP.py similarity index 73% rename from tests/ModemMode/test_ModemMode.py rename to tests/PPP/test_IPPP.py index c942e022..4710e632 100644 --- a/tests/ModemMode/test_ModemMode.py +++ b/tests/PPP/test_IPPP.py @@ -10,12 +10,12 @@ sys.path.append(".") sys.path.append("..") sys.path.append("../..") -from Hologram.Network.Modem.ModemMode.ModemMode import ModemMode +from Hologram.PPP import IPPP -class TestModemMode: +class TestIPPP: def test_modem_mode_create(self): - modem_mode = ModemMode(device_name='/dev/ttyUSB0', baud_rate='9600') + modem_mode = IPPP(device_name='/dev/ttyUSB0', baud_rate='9600') assert modem_mode.device_name == '/dev/ttyUSB0' assert modem_mode.baud_rate == '9600' diff --git a/tests/ModemMode/test_PPP.py b/tests/PPP/test_PPP.py similarity index 92% rename from tests/ModemMode/test_PPP.py rename to tests/PPP/test_PPP.py index 1f68c8a8..ec351f4f 100644 --- a/tests/ModemMode/test_PPP.py +++ b/tests/PPP/test_PPP.py @@ -11,7 +11,7 @@ sys.path.append(".") sys.path.append("..") sys.path.append("../..") -from Hologram.Network.Modem.ModemMode.MockPPP import MockPPP +from tests.PPP.MockPPP import MockPPP class TestPPP: diff --git a/tests/init.py b/tests/init.py new file mode 100644 index 00000000..e69de29b From a80126c32b415efe6f68ab546d5aa6c49b4b8590 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:30:44 -0500 Subject: [PATCH 02/23] move modem modem setter --- Hologram/Modem/UBlox/Nova.py | 11 +++++++++++ Hologram/Modem/__init__.py | 9 --------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Hologram/Modem/UBlox/Nova.py b/Hologram/Modem/UBlox/Nova.py index 34aed843..409b525a 100644 --- a/Hologram/Modem/UBlox/Nova.py +++ b/Hologram/Modem/UBlox/Nova.py @@ -13,6 +13,8 @@ from Hologram.Exceptions.HologramError import NetworkError from Hologram.Event import Event +import time + DEFAULT_NOVA_TIMEOUT = 200 class Nova(Modem): @@ -78,6 +80,15 @@ def modem_mode(self): self.logger.error(repr(e)) return mode_number + @modem_mode.setter + def modem_mode(self, mode): + self.set('+UUSBCONF', str(mode)) + self.logger.info('Restarting modem') + self.reset() + self.logger.info('Modem restarted') + self.closeSerialPort() + time.sleep(Modem.DEFAULT_MODEM_RESTART_TIME) + @property def version(self): return self._basic_command('I9') diff --git a/Hologram/Modem/__init__.py b/Hologram/Modem/__init__.py index 613016fa..5e567a7f 100644 --- a/Hologram/Modem/__init__.py +++ b/Hologram/Modem/__init__.py @@ -891,15 +891,6 @@ def ppp(self): def at_sockets_available(self): return self._at_sockets_available - @modem_mode.setter - def modem_mode(self, mode): - self.set('+UUSBCONF', str(mode)) - self.logger.info('Restarting modem') - self.reset() - self.logger.info('Modem restarted') - self.closeSerialPort() - time.sleep(Modem.DEFAULT_MODEM_RESTART_TIME) - @property def localIPAddress(self): if self._ppp: From 363cf44f9ef4e07fb6640ae33bc92403c5f066cf Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:32:53 -0500 Subject: [PATCH 03/23] fix import --- Hologram/Modem/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Hologram/Modem/__init__.py b/Hologram/Modem/__init__.py index 5e567a7f..4d36d93d 100644 --- a/Hologram/Modem/__init__.py +++ b/Hologram/Modem/__init__.py @@ -7,7 +7,6 @@ # # LICENSE: Distributed under the terms of the MIT License -from Hologram.Modem import IModem from Hologram.PPP.PPP import PPP from Hologram.Utils import ModemResult from Hologram.Utils import SMS From 49b9cc79fe784baf7e6047a9f3ddc87969cb801c Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:34:33 -0500 Subject: [PATCH 04/23] fix path --- Hologram/PPP/PPP.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hologram/PPP/PPP.py b/Hologram/PPP/PPP.py index 373f4ad6..ffb7be5d 100644 --- a/Hologram/PPP/PPP.py +++ b/Hologram/PPP/PPP.py @@ -10,7 +10,7 @@ import psutil from Hologram.PPP.pppd import PPPConnection from Hologram.PPP import IPPP -from Hologram.Util.Route import Route +from Hologram.Utils.Route import Route from Hologram.Exceptions.HologramError import PPPError DEFAULT_PPP_TIMEOUT = 200 From 5d9320af2c74ac92d57fb955ab5fa117c980cdd0 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:38:41 -0500 Subject: [PATCH 05/23] fix modem import --- Hologram/Network.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Hologram/Network.py b/Hologram/Network.py index a037a883..4a566578 100644 --- a/Hologram/Network.py +++ b/Hologram/Network.py @@ -11,7 +11,10 @@ from Hologram.Event import Event from Hologram.Exceptions.HologramError import NetworkError from Hologram.Utils.Route import Route -from Hologram.Modem import Modem, E303, MS2131, E372, BG96, Nova_U201, NovaM, DriverLoader +from Hologram.Modem import Modem, DriverLoader +from Hologram.Modem.Huawei import E303, MS2131, E372 +from Hologram.Modem.Quectel import BG96 +from Hologram.Modem.UBlox import Nova_U201, NovaM import logging import time from logging import NullHandler From 5654285fe10e6ae914ee05a1fb41cb6ae3083784 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:45:23 -0500 Subject: [PATCH 06/23] fix nova path and move single file dirs down --- Hologram/{Api => }/Api.py | 0 Hologram/Api/__init__.py | 1 - Hologram/{Exceptions/HologramError.py => Exceptions.py} | 0 Hologram/Exceptions/__init__.py | 2 -- Hologram/Modem/UBlox/NovaM.py | 2 +- Hologram/Modem/UBlox/Nova_U201.py | 2 +- 6 files changed, 2 insertions(+), 5 deletions(-) rename Hologram/{Api => }/Api.py (100%) delete mode 100644 Hologram/Api/__init__.py rename Hologram/{Exceptions/HologramError.py => Exceptions.py} (100%) delete mode 100644 Hologram/Exceptions/__init__.py diff --git a/Hologram/Api/Api.py b/Hologram/Api.py similarity index 100% rename from Hologram/Api/Api.py rename to Hologram/Api.py diff --git a/Hologram/Api/__init__.py b/Hologram/Api/__init__.py deleted file mode 100644 index 1b5e07ab..00000000 --- a/Hologram/Api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .Api import * diff --git a/Hologram/Exceptions/HologramError.py b/Hologram/Exceptions.py similarity index 100% rename from Hologram/Exceptions/HologramError.py rename to Hologram/Exceptions.py diff --git a/Hologram/Exceptions/__init__.py b/Hologram/Exceptions/__init__.py deleted file mode 100644 index 139597f9..00000000 --- a/Hologram/Exceptions/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/Hologram/Modem/UBlox/NovaM.py b/Hologram/Modem/UBlox/NovaM.py index c9fb7372..8d672fdb 100644 --- a/Hologram/Modem/UBlox/NovaM.py +++ b/Hologram/Modem/UBlox/NovaM.py @@ -8,7 +8,7 @@ # LICENSE: Distributed under the terms of the MIT License # -from Hologram.Modem.Nova import Nova +from Hologram.Modem.UBlox.Nova import Nova from Hologram.Event import Event from Hologram.Exceptions.HologramError import NetworkError from Hologram.Utils import ModemResult diff --git a/Hologram/Modem/UBlox/Nova_U201.py b/Hologram/Modem/UBlox/Nova_U201.py index e93df9de..537463ea 100644 --- a/Hologram/Modem/UBlox/Nova_U201.py +++ b/Hologram/Modem/UBlox/Nova_U201.py @@ -8,7 +8,7 @@ # LICENSE: Distributed under the terms of the MIT License # -from Hologram.Modem.Nova import Nova +from Hologram.Modem.UBlox.Nova import Nova from Hologram.Exceptions.HologramError import SerialError from Hologram.Event import Event from Hologram.Utils import Location From b4ab21322aa03bbb82af6fe31adb1a91272d8b5a Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 18:47:57 -0500 Subject: [PATCH 07/23] fix exception path --- Hologram/Api.py | 2 +- Hologram/Authentication/CSRPSKAuthentication.py | 2 +- Hologram/CustomCloud.py | 2 +- Hologram/HologramCloud.py | 2 +- Hologram/Modem/Quectel/BG96.py | 2 +- Hologram/Modem/UBlox/Nova.py | 2 +- Hologram/Modem/UBlox/NovaM.py | 2 +- Hologram/Modem/UBlox/Nova_U201.py | 2 +- Hologram/Modem/__init__.py | 2 +- Hologram/Network.py | 2 +- Hologram/PPP/PPP.py | 2 +- Hologram/PPP/pppd.py | 2 +- scripts/hologram | 2 +- scripts/hologram_activate.py | 2 +- scripts/hologram_modem.py | 2 +- scripts/hologram_network.py | 2 +- scripts/hologram_send.py | 2 +- tests/Modem/test_Modem.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Hologram/Api.py b/Hologram/Api.py index cfb524cb..7133efe5 100644 --- a/Hologram/Api.py +++ b/Hologram/Api.py @@ -9,7 +9,7 @@ import logging from logging import NullHandler -from Hologram.Exceptions.HologramError import ApiError +from Hologram.Exceptions import ApiError import requests HOLOGRAM_REST_API_BASEURL = 'https://dashboard.hologram.io/api/1' diff --git a/Hologram/Authentication/CSRPSKAuthentication.py b/Hologram/Authentication/CSRPSKAuthentication.py index a38f6e7b..dcfaec9c 100644 --- a/Hologram/Authentication/CSRPSKAuthentication.py +++ b/Hologram/Authentication/CSRPSKAuthentication.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License # import json -from Hologram.Exceptions.HologramError import AuthenticationError +from Hologram.Exceptions import AuthenticationError from Hologram.Authentication.HologramAuthentication import HologramAuthentication DEVICE_KEY_LEN = 8 diff --git a/Hologram/CustomCloud.py b/Hologram/CustomCloud.py index 919bcdcc..64406759 100644 --- a/Hologram/CustomCloud.py +++ b/Hologram/CustomCloud.py @@ -11,7 +11,7 @@ import socket import threading from Hologram.Cloud import Cloud -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError MAX_RECEIVE_BYTES = 1024 MAX_QUEUED_CONNECTIONS = 5 diff --git a/Hologram/HologramCloud.py b/Hologram/HologramCloud.py index d8bc60be..14fc4ed7 100755 --- a/Hologram/HologramCloud.py +++ b/Hologram/HologramCloud.py @@ -14,7 +14,7 @@ from Hologram.CustomCloud import CustomCloud from HologramAuth import TOTPAuthentication, SIMOTPAuthentication from Hologram.Authentication import CSRPSKAuthentication -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError DEFAULT_SEND_MESSAGE_TIMEOUT = 5 HOLOGRAM_HOST_SEND = 'cloudsocket.hologram.io' diff --git a/Hologram/Modem/Quectel/BG96.py b/Hologram/Modem/Quectel/BG96.py index d071653c..e2903bc7 100644 --- a/Hologram/Modem/Quectel/BG96.py +++ b/Hologram/Modem/Quectel/BG96.py @@ -15,7 +15,7 @@ from Hologram.Modem import Modem from Hologram.Event import Event from Hologram.Utils import ModemResult -from Hologram.Exceptions.HologramError import SerialError, NetworkError +from Hologram.Exceptions import SerialError, NetworkError DEFAULT_BG96_TIMEOUT = 200 diff --git a/Hologram/Modem/UBlox/Nova.py b/Hologram/Modem/UBlox/Nova.py index 409b525a..78787fb5 100644 --- a/Hologram/Modem/UBlox/Nova.py +++ b/Hologram/Modem/UBlox/Nova.py @@ -10,7 +10,7 @@ from Hologram.Modem import Modem from Hologram.Utils import ModemResult -from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Exceptions import NetworkError from Hologram.Event import Event import time diff --git a/Hologram/Modem/UBlox/NovaM.py b/Hologram/Modem/UBlox/NovaM.py index 8d672fdb..7c7d2d04 100644 --- a/Hologram/Modem/UBlox/NovaM.py +++ b/Hologram/Modem/UBlox/NovaM.py @@ -10,7 +10,7 @@ from Hologram.Modem.UBlox.Nova import Nova from Hologram.Event import Event -from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Exceptions import NetworkError from Hologram.Utils import ModemResult DEFAULT_NOVAM_TIMEOUT = 200 diff --git a/Hologram/Modem/UBlox/Nova_U201.py b/Hologram/Modem/UBlox/Nova_U201.py index 537463ea..602618c6 100644 --- a/Hologram/Modem/UBlox/Nova_U201.py +++ b/Hologram/Modem/UBlox/Nova_U201.py @@ -9,7 +9,7 @@ # from Hologram.Modem.UBlox.Nova import Nova -from Hologram.Exceptions.HologramError import SerialError +from Hologram.Exceptions import SerialError from Hologram.Event import Event from Hologram.Utils import Location from Hologram.Utils import ModemResult diff --git a/Hologram/Modem/__init__.py b/Hologram/Modem/__init__.py index 4d36d93d..c8cb4004 100644 --- a/Hologram/Modem/__init__.py +++ b/Hologram/Modem/__init__.py @@ -11,7 +11,7 @@ from Hologram.Utils import ModemResult from Hologram.Utils import SMS from Hologram.Event import Event -from Hologram.Exceptions.HologramError import SerialError, HologramError, NetworkError, PPPError +from Hologram.Exceptions import SerialError, HologramError, NetworkError, PPPError from collections import deque diff --git a/Hologram/Network.py b/Hologram/Network.py index 4a566578..b38d2cfe 100644 --- a/Hologram/Network.py +++ b/Hologram/Network.py @@ -9,7 +9,7 @@ # from Hologram.Event import Event -from Hologram.Exceptions.HologramError import NetworkError +from Hologram.Exceptions import NetworkError from Hologram.Utils.Route import Route from Hologram.Modem import Modem, DriverLoader from Hologram.Modem.Huawei import E303, MS2131, E372 diff --git a/Hologram/PPP/PPP.py b/Hologram/PPP/PPP.py index ffb7be5d..56b4f070 100644 --- a/Hologram/PPP/PPP.py +++ b/Hologram/PPP/PPP.py @@ -11,7 +11,7 @@ from Hologram.PPP.pppd import PPPConnection from Hologram.PPP import IPPP from Hologram.Utils.Route import Route -from Hologram.Exceptions.HologramError import PPPError +from Hologram.Exceptions import PPPError DEFAULT_PPP_TIMEOUT = 200 DEFAULT_PPP_INTERFACE = 'ppp0' diff --git a/Hologram/PPP/pppd.py b/Hologram/PPP/pppd.py index e0793dcb..1e042ea2 100644 --- a/Hologram/PPP/pppd.py +++ b/Hologram/PPP/pppd.py @@ -17,7 +17,7 @@ import threading import errno from subprocess import Popen, PIPE, STDOUT -from Hologram.Exceptions.HologramError import PPPError, PPPConnectionError +from Hologram.Exceptions import PPPError, PPPConnectionError __version__ = '1.0.3' diff --git a/scripts/hologram b/scripts/hologram index 92e32682..5b616aa0 100755 --- a/scripts/hologram +++ b/scripts/hologram @@ -14,7 +14,7 @@ from argparse import RawTextHelpFormatter import logging import sys from Hologram.CustomCloud import CustomCloud -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError from scripts.hologram_send import parse_hologram_send_args from scripts.hologram_send import run_hologram_send diff --git a/scripts/hologram_activate.py b/scripts/hologram_activate.py index de7723d3..b8bfbee6 100644 --- a/scripts/hologram_activate.py +++ b/scripts/hologram_activate.py @@ -17,7 +17,7 @@ from Hologram.HologramCloud import HologramCloud from Hologram.Api import Api -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError from .hologram_util import VAction CHECK_LIVE_SIM_STATE_MAX_TIMEOUT = 120 # 2 mins for max timeout diff --git a/scripts/hologram_modem.py b/scripts/hologram_modem.py index 1287c5a1..efac3f2f 100644 --- a/scripts/hologram_modem.py +++ b/scripts/hologram_modem.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License from Hologram.CustomCloud import CustomCloud -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError from .hologram_util import handle_timeout from .hologram_util import VAction import json diff --git a/scripts/hologram_network.py b/scripts/hologram_network.py index 45447b11..e6d737fc 100644 --- a/scripts/hologram_network.py +++ b/scripts/hologram_network.py @@ -9,7 +9,7 @@ # LICENSE: Distributed under the terms of the MIT License from Hologram.CustomCloud import CustomCloud -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError from .hologram_util import VAction import psutil diff --git a/scripts/hologram_send.py b/scripts/hologram_send.py index 5c328e34..5bfe32a8 100644 --- a/scripts/hologram_send.py +++ b/scripts/hologram_send.py @@ -12,7 +12,7 @@ from Hologram.CustomCloud import CustomCloud from Hologram.HologramCloud import HologramCloud -from Hologram.Exceptions.HologramError import HologramError +from Hologram.Exceptions import HologramError from .hologram_util import VAction import argparse diff --git a/tests/Modem/test_Modem.py b/tests/Modem/test_Modem.py index 7b1b4fac..57ace005 100644 --- a/tests/Modem/test_Modem.py +++ b/tests/Modem/test_Modem.py @@ -13,7 +13,7 @@ sys.path.append(".") sys.path.append("..") sys.path.append("../..") -from Hologram.Exceptions.HologramError import SerialError +from Hologram.Exceptions import SerialError from Hologram.Modem import Modem from Hologram.Utils import ModemResult From c0da7f6145b204cff13eddb55ec7211ec187bcbc Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 19:23:47 -0500 Subject: [PATCH 08/23] redo network handling --- Hologram/Cloud.py | 43 ++++++++++++++++++---------- Hologram/CustomCloud.py | 6 ++-- Hologram/HologramCloud.py | 5 ++-- tests/Network/test_NetworkManager.py | 40 -------------------------- 4 files changed, 32 insertions(+), 62 deletions(-) delete mode 100644 tests/Network/test_NetworkManager.py diff --git a/Hologram/Cloud.py b/Hologram/Cloud.py index 680dfcb3..c72b4a27 100644 --- a/Hologram/Cloud.py +++ b/Hologram/Cloud.py @@ -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' @@ -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__) @@ -33,7 +34,7 @@ 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 @@ -41,17 +42,22 @@ def __initialize_host_and_port(self, send_host, send_port, receive_host, receive 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): @@ -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) @@ -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() \ No newline at end of file diff --git a/Hologram/CustomCloud.py b/Hologram/CustomCloud.py index 64406759..8ea5b8a6 100644 --- a/Hologram/CustomCloud.py +++ b/Hologram/CustomCloud.py @@ -22,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): diff --git a/Hologram/HologramCloud.py b/Hologram/HologramCloud.py index 14fc4ed7..e08fb424 100755 --- a/Hologram/HologramCloud.py +++ b/Hologram/HologramCloud.py @@ -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) diff --git a/tests/Network/test_NetworkManager.py b/tests/Network/test_NetworkManager.py deleted file mode 100644 index d941a45b..00000000 --- a/tests/Network/test_NetworkManager.py +++ /dev/null @@ -1,40 +0,0 @@ -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# LICENSE: Distributed under the terms of the MIT License -# -# test_NetworkManager.py - This file implements unit tests for the NetworkManager class. - -import sys -import pytest - -sys.path.append(".") -sys.path.append("..") -sys.path.append("../..") -from Hologram.Network import NetworkManager - -class TestNetworkManager: - - def test_create_non_network(self): - networkManager = NetworkManager.NetworkManager(None, '') - assert networkManager.networkActive - assert repr(networkManager) == 'Network Agnostic Mode' - - def test_invalid_create(self): - with pytest.raises(Exception, match = 'Invalid network type: invalid'): - networkManager = NetworkManager.NetworkManager(None, 'invalid') - - def test_invalid_ppp_create(self): - with pytest.raises(Exception, match = 'Invalid network type: invalid-ppp'): - networkManager = NetworkManager.NetworkManager(None, 'invalid-ppp') - - def test_network_connected(self): - networkManager = NetworkManager.NetworkManager(None, '') - networkManager.networkConnected() - assert networkManager.networkActive - - def test_network_disconnected(self): - networkManager = NetworkManager.NetworkManager(None, '') - networkManager.networkDisconnected() - assert networkManager.networkActive == False From 03a5d30d75f8613a2b9cd1830ca8c6dd562eca08 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Tue, 14 Jul 2020 19:28:13 -0500 Subject: [PATCH 09/23] remove unused tests --- tests/Network/test_Cellular.py | 20 -------------------- tests/Network/test_Ethernet.py | 34 ---------------------------------- 2 files changed, 54 deletions(-) delete mode 100644 tests/Network/test_Cellular.py delete mode 100644 tests/Network/test_Ethernet.py diff --git a/tests/Network/test_Cellular.py b/tests/Network/test_Cellular.py deleted file mode 100644 index 52f6e953..00000000 --- a/tests/Network/test_Cellular.py +++ /dev/null @@ -1,20 +0,0 @@ -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# LICENSE: Distributed under the terms of the MIT License -# -# test_Cellular.py - This file implements unit tests for the Cellular class. - -import sys -import pytest - -sys.path.append(".") -sys.path.append("..") -sys.path.append("../..") -from Hologram.Network import Cellular - -class TestCellular: - - def test_invalid_cellular_type(self): - pass diff --git a/tests/Network/test_Ethernet.py b/tests/Network/test_Ethernet.py deleted file mode 100644 index f68634e8..00000000 --- a/tests/Network/test_Ethernet.py +++ /dev/null @@ -1,34 +0,0 @@ -# Author: Hologram -# -# Copyright 2016 - Hologram (Konekt, Inc.) -# -# LICENSE: Distributed under the terms of the MIT License -# -# test_Ethernet.py - This file implements unit tests for the Ethernet class. - -import sys -import pytest - -sys.path.append(".") -sys.path.append("..") -sys.path.append("../..") -from Hologram.Network import Ethernet - -class TestEthernet: - - def test_Ethernet(self): - ethernet = Ethernet.Ethernet() - assert ethernet.interfaceName == 'eth0' - - ethernet.interfaceName = 'eth1' - assert ethernet.interfaceName == 'eth1' - - def test_Ethernet_with_specified_interface(self): - - ethernet = Ethernet.Ethernet(interfaceName = 'eth2') - assert ethernet.interfaceName == 'eth2' - - def test_get_invalid_signal_strength(self): - ethernet = Ethernet.Ethernet() - with pytest.raises(Exception, match = 'Ethernet mode doesn\'t support this call'): - connectionStatus = ethernet.getAvgSignalStrength() From 9afb1696baff17435fbf608bd5dd36bfc02bdbe0 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 11:48:37 -0500 Subject: [PATCH 10/23] mock out modem scan --- tests/{MessageMode => Cloud}/test_Cloud.py | 18 +++++++++++++----- .../{MessageMode => Cloud}/test_CustomCloud.py | 18 +++++++++++++----- .../test_HologramCloud.py | 14 +++++++++++--- 3 files changed, 37 insertions(+), 13 deletions(-) rename tests/{MessageMode => Cloud}/test_Cloud.py (76%) rename tests/{MessageMode => Cloud}/test_CustomCloud.py (79%) rename tests/{MessageMode => Cloud}/test_HologramCloud.py (84%) diff --git a/tests/MessageMode/test_Cloud.py b/tests/Cloud/test_Cloud.py similarity index 76% rename from tests/MessageMode/test_Cloud.py rename to tests/Cloud/test_Cloud.py index c7dbda11..6a8340a7 100644 --- a/tests/MessageMode/test_Cloud.py +++ b/tests/Cloud/test_Cloud.py @@ -13,10 +13,18 @@ sys.path.append("../..") from Hologram.Authentication import * from Hologram.Cloud import Cloud +from Hologram.Network import Network class TestCloud: - def test_create_send(self): + def mock_scan(self, network): + return ['MockModem'] + + @pytest.fixture + def no_modem(self, monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) + + def test_create_send(self, no_modem): cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) assert cloud.send_host == '127.0.0.1' @@ -24,7 +32,7 @@ def test_create_send(self): assert cloud.receive_host == '' assert cloud.receive_port == 0 - def test_create_receive(self): + def test_create_receive(self, no_modem): cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) assert cloud.send_host == '' @@ -32,20 +40,20 @@ def test_create_receive(self): assert cloud.receive_host == '127.0.0.1' assert cloud.receive_port == 9999 - def test_invalid_send_message(self): + def test_invalid_send_message(self, no_modem): cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): cloud.sendMessage("hello SMS") - def test_invalid_send_sms(self): + def test_invalid_send_sms(self, no_modem): cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): cloud.sendSMS('+12345678900', 'hello SMS') # This is good for testing if we updated the internal SDK version numbers before release. - def test_sdk_version(self): + def test_sdk_version(self, no_modem): cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) assert cloud.version == '0.9.0' diff --git a/tests/MessageMode/test_CustomCloud.py b/tests/Cloud/test_CustomCloud.py similarity index 79% rename from tests/MessageMode/test_CustomCloud.py rename to tests/Cloud/test_CustomCloud.py index d7cd9e45..68015789 100644 --- a/tests/MessageMode/test_CustomCloud.py +++ b/tests/Cloud/test_CustomCloud.py @@ -13,10 +13,18 @@ sys.path.append("../..") from Hologram.Authentication import * from Hologram.CustomCloud import CustomCloud +from Hologram.Network import Network class TestCustomCloud: - def test_create_send(self): + def mock_scan(self, network): + return ['MockModem'] + + @pytest.fixture + def no_modem(self, monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) + + def test_create_send(self, no_modem): customCloud = CustomCloud(None, send_host='127.0.0.1', send_port=9999, enable_inbound=False) @@ -25,7 +33,7 @@ def test_create_send(self): assert customCloud.receive_host == '' assert customCloud.receive_port == 0 - def test_create_receive(self): + def test_create_receive(self, no_modem): customCloud = CustomCloud(None, receive_host='127.0.0.1', receive_port=9999, enable_inbound=False) @@ -34,19 +42,19 @@ def test_create_receive(self): assert customCloud.receive_host == '127.0.0.1' assert customCloud.receive_port == 9999 - def test_enable_inbound(self): + def test_enable_inbound(self, no_modem): with pytest.raises(Exception, match='Must set receive host and port for inbound connection'): customCloud = CustomCloud(None, send_host='receive.com', send_port=9999, enable_inbound=True) - def test_invalid_send_host_and_port(self): + def test_invalid_send_host_and_port(self, no_modem): customCloud = CustomCloud(None, receive_host='receive.com', receive_port=9999) with pytest.raises(Exception, match = 'Send host and port must be set before making this operation'): customCloud.sendMessage("hello") - def test_invalid_send_sms(self): + def test_invalid_send_sms(self, no_modem): customCloud = CustomCloud(None, 'test.com', 9999) temp = "hello" diff --git a/tests/MessageMode/test_HologramCloud.py b/tests/Cloud/test_HologramCloud.py similarity index 84% rename from tests/MessageMode/test_HologramCloud.py rename to tests/Cloud/test_HologramCloud.py index e2d328d8..fa0633a9 100644 --- a/tests/MessageMode/test_HologramCloud.py +++ b/tests/Cloud/test_HologramCloud.py @@ -13,12 +13,20 @@ sys.path.append("../..") from Hologram.Authentication import * from Hologram.HologramCloud import HologramCloud +from Hologram.Network import Network credentials = {'devicekey':'12345678'} class TestHologramCloud: - def test_create(self): + def mock_scan(self, network): + return ['MockModem'] + + @pytest.fixture + def no_modem(self, monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) + + def test_create(self, no_modem): hologram = HologramCloud(credentials, enable_inbound = False) assert hologram.send_host == 'cloudsocket.hologram.io' @@ -26,7 +34,7 @@ def test_create(self): assert hologram.receive_host == '0.0.0.0' assert hologram.receive_port == 4010 - def test_invalid_sms_length(self): + def test_invalid_sms_length(self, no_modem): hologram = HologramCloud(credentials, authentication_type='csrpsk', enable_inbound = False) @@ -34,7 +42,7 @@ def test_invalid_sms_length(self): with pytest.raises(Exception, match = 'SMS cannot be more than 160 characters long'): hologram.sendSMS('+1234567890', temp) - def test_get_result_string(self): + def test_get_result_string(self, no_modem): hologram = HologramCloud(credentials, enable_inbound = False) From 5db8cfa895e2f92cbda23682bacfa2494fa9dca9 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 12:06:58 -0500 Subject: [PATCH 11/23] work on tests --- tests/Cloud/test_Cloud.py | 60 ++++++++++++++-------------- tests/Cloud/test_CustomCloud.py | 66 +++++++++++++++---------------- tests/Cloud/test_HologramCloud.py | 58 +++++++++++++-------------- tests/Network/test_Network.py | 15 +------ tests/PPP/test_IPPP.py | 2 +- 5 files changed, 92 insertions(+), 109 deletions(-) diff --git a/tests/Cloud/test_Cloud.py b/tests/Cloud/test_Cloud.py index 6a8340a7..5d82e97d 100644 --- a/tests/Cloud/test_Cloud.py +++ b/tests/Cloud/test_Cloud.py @@ -15,45 +15,43 @@ from Hologram.Cloud import Cloud from Hologram.Network import Network -class TestCloud: +def mock_scan(): + return ['MockModem'] - def mock_scan(self, network): - return ['MockModem'] +@pytest.fixture +def no_modem(monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) - @pytest.fixture - def no_modem(self, monkeypatch): - monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) +def test_create_send(no_modem): + cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) - def test_create_send(self, no_modem): - cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) + assert cloud.send_host == '127.0.0.1' + assert cloud.send_port == 9999 + assert cloud.receive_host == '' + assert cloud.receive_port == 0 - assert cloud.send_host == '127.0.0.1' - assert cloud.send_port == 9999 - assert cloud.receive_host == '' - assert cloud.receive_port == 0 +def test_create_receive(no_modem): + cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) - def test_create_receive(self, no_modem): - cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) + assert cloud.send_host == '' + assert cloud.send_port == 0 + assert cloud.receive_host == '127.0.0.1' + assert cloud.receive_port == 9999 - assert cloud.send_host == '' - assert cloud.send_port == 0 - assert cloud.receive_host == '127.0.0.1' - assert cloud.receive_port == 9999 +def test_invalid_send_message(no_modem): + cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) - def test_invalid_send_message(self, no_modem): - cloud = Cloud(None, receive_host = '127.0.0.1', receive_port = 9999) + with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): + cloud.sendMessage("hello SMS") - with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): - cloud.sendMessage("hello SMS") +def test_invalid_send_sms(no_modem): + cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) - def test_invalid_send_sms(self, no_modem): - cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) + with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): + cloud.sendSMS('+12345678900', 'hello SMS') - with pytest.raises(Exception, match = 'Must instantiate a Cloud type'): - cloud.sendSMS('+12345678900', 'hello SMS') +# This is good for testing if we updated the internal SDK version numbers before release. +def test_sdk_version(no_modem): + cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) - # This is good for testing if we updated the internal SDK version numbers before release. - def test_sdk_version(self, no_modem): - cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) - - assert cloud.version == '0.9.0' + assert cloud.version == '0.9.0' diff --git a/tests/Cloud/test_CustomCloud.py b/tests/Cloud/test_CustomCloud.py index 68015789..1b4c814d 100644 --- a/tests/Cloud/test_CustomCloud.py +++ b/tests/Cloud/test_CustomCloud.py @@ -15,48 +15,46 @@ from Hologram.CustomCloud import CustomCloud from Hologram.Network import Network -class TestCustomCloud: +def mock_scan(self): + return ['MockModem'] - def mock_scan(self, network): - return ['MockModem'] +@pytest.fixture +def no_modem(monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) - @pytest.fixture - def no_modem(self, monkeypatch): - monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) +def test_create_send(no_modem): + customCloud = CustomCloud(None, send_host='127.0.0.1', + send_port=9999, enable_inbound=False) - def test_create_send(self, no_modem): - customCloud = CustomCloud(None, send_host='127.0.0.1', - send_port=9999, enable_inbound=False) + assert customCloud.send_host == '127.0.0.1' + assert customCloud.send_port == 9999 + assert customCloud.receive_host == '' + assert customCloud.receive_port == 0 - assert customCloud.send_host == '127.0.0.1' - assert customCloud.send_port == 9999 - assert customCloud.receive_host == '' - assert customCloud.receive_port == 0 +def test_create_receive(no_modem): + customCloud = CustomCloud(None, receive_host='127.0.0.1', + receive_port=9999, enable_inbound=False) - def test_create_receive(self, no_modem): - customCloud = CustomCloud(None, receive_host='127.0.0.1', - receive_port=9999, enable_inbound=False) + assert customCloud.send_host == '' + assert customCloud.send_port == 0 + assert customCloud.receive_host == '127.0.0.1' + assert customCloud.receive_port == 9999 - assert customCloud.send_host == '' - assert customCloud.send_port == 0 - assert customCloud.receive_host == '127.0.0.1' - assert customCloud.receive_port == 9999 +def test_enable_inbound(no_modem): - def test_enable_inbound(self, no_modem): + with pytest.raises(Exception, match='Must set receive host and port for inbound connection'): + customCloud = CustomCloud(None, send_host='receive.com', + send_port=9999, enable_inbound=True) - with pytest.raises(Exception, match='Must set receive host and port for inbound connection'): - customCloud = CustomCloud(None, send_host='receive.com', - send_port=9999, enable_inbound=True) +def test_invalid_send_host_and_port(no_modem): + customCloud = CustomCloud(None, receive_host='receive.com', receive_port=9999) - def test_invalid_send_host_and_port(self, no_modem): - customCloud = CustomCloud(None, receive_host='receive.com', receive_port=9999) + with pytest.raises(Exception, match = 'Send host and port must be set before making this operation'): + customCloud.sendMessage("hello") - with pytest.raises(Exception, match = 'Send host and port must be set before making this operation'): - customCloud.sendMessage("hello") +def test_invalid_send_sms(no_modem): + customCloud = CustomCloud(None, 'test.com', 9999) - def test_invalid_send_sms(self, no_modem): - customCloud = CustomCloud(None, 'test.com', 9999) - - temp = "hello" - with pytest.raises(NotImplementedError, match='Cannot send SMS via custom cloud'): - customCloud.sendSMS('+1234567890', temp) + temp = "hello" + with pytest.raises(NotImplementedError, match='Cannot send SMS via custom cloud'): + customCloud.sendSMS('+1234567890', temp) diff --git a/tests/Cloud/test_HologramCloud.py b/tests/Cloud/test_HologramCloud.py index fa0633a9..95077f3c 100644 --- a/tests/Cloud/test_HologramCloud.py +++ b/tests/Cloud/test_HologramCloud.py @@ -17,42 +17,40 @@ credentials = {'devicekey':'12345678'} -class TestHologramCloud: +def mock_scan(network): + return ['MockModem'] - def mock_scan(self, network): - return ['MockModem'] +@pytest.fixture +def no_modem(monkeypatch): + monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) - @pytest.fixture - def no_modem(self, monkeypatch): - monkeypatch.setattr(Network, '_scan_for_modems', self.mock_scan) +def test_create(no_modem): + hologram = HologramCloud(credentials, enable_inbound = False) - def test_create(self, no_modem): - hologram = HologramCloud(credentials, enable_inbound = False) + assert hologram.send_host == 'cloudsocket.hologram.io' + assert hologram.send_port == 9999 + assert hologram.receive_host == '0.0.0.0' + assert hologram.receive_port == 4010 - assert hologram.send_host == 'cloudsocket.hologram.io' - assert hologram.send_port == 9999 - assert hologram.receive_host == '0.0.0.0' - assert hologram.receive_port == 4010 +def test_invalid_sms_length(no_modem): - def test_invalid_sms_length(self, no_modem): + hologram = HologramCloud(credentials, authentication_type='csrpsk', enable_inbound = False) - hologram = HologramCloud(credentials, authentication_type='csrpsk', enable_inbound = False) + temp = '111111111234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' + with pytest.raises(Exception, match = 'SMS cannot be more than 160 characters long'): + hologram.sendSMS('+1234567890', temp) - temp = '111111111234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' - with pytest.raises(Exception, match = 'SMS cannot be more than 160 characters long'): - hologram.sendSMS('+1234567890', temp) +def test_get_result_string(no_modem): - def test_get_result_string(self, no_modem): + hologram = HologramCloud(credentials, enable_inbound = False) - hologram = HologramCloud(credentials, enable_inbound = False) - - assert hologram.getResultString(-1) == 'Unknown error' - assert hologram.getResultString(0) == 'Message sent successfully' - assert hologram.getResultString(1) == 'Connection was closed so we couldn\'t read the whole message' - assert hologram.getResultString(2) == 'Failed to parse the message' - assert hologram.getResultString(3) == 'Auth section of the message was invalid' - assert hologram.getResultString(4) == 'Payload type was invalid' - assert hologram.getResultString(5) == 'Protocol type was invalid' - assert hologram.getResultString(6) == 'Internal error in Hologram Cloud' - assert hologram.getResultString(7) == 'Metadata was formatted incorrectly' - assert hologram.getResultString(8) == 'Topic was formatted incorrectly' + assert hologram.getResultString(-1) == 'Unknown error' + assert hologram.getResultString(0) == 'Message sent successfully' + assert hologram.getResultString(1) == 'Connection was closed so we couldn\'t read the whole message' + assert hologram.getResultString(2) == 'Failed to parse the message' + assert hologram.getResultString(3) == 'Auth section of the message was invalid' + assert hologram.getResultString(4) == 'Payload type was invalid' + assert hologram.getResultString(5) == 'Protocol type was invalid' + assert hologram.getResultString(6) == 'Internal error in Hologram Cloud' + assert hologram.getResultString(7) == 'Metadata was formatted incorrectly' + assert hologram.getResultString(8) == 'Topic was formatted incorrectly' diff --git a/tests/Network/test_Network.py b/tests/Network/test_Network.py index ce36fdfc..cc2abf68 100644 --- a/tests/Network/test_Network.py +++ b/tests/Network/test_Network.py @@ -14,17 +14,6 @@ sys.path.append("../..") from Hologram.Network import Network -class TestNetwork: - def test_create_network(self): - network = Network() - - def test_get_invalid_connection_status(self): - network = Network() - with pytest.raises(Exception, match = 'Must instantiate a defined Network type'): - connectionStatus = network.getConnectionStatus() - - def test_get_invalid_signal_strength(self): - network = Network() - with pytest.raises(Exception, match = 'Must instantiate a defined Network type'): - connectionStatus = network.getSignalStrength() +def test_create_network(self): + network = Network() diff --git a/tests/PPP/test_IPPP.py b/tests/PPP/test_IPPP.py index 4710e632..f4e2f623 100644 --- a/tests/PPP/test_IPPP.py +++ b/tests/PPP/test_IPPP.py @@ -15,7 +15,7 @@ class TestIPPP: def test_modem_mode_create(self): - modem_mode = IPPP(device_name='/dev/ttyUSB0', baud_rate='9600') + modem_mode = IPPP(device_name='/dev/ttyUSB0', baud_rate='9600',chatscript_file='test') assert modem_mode.device_name == '/dev/ttyUSB0' assert modem_mode.baud_rate == '9600' From fa6466fe22e9df255dc4836b1e62eddf55054015 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 12:14:38 -0500 Subject: [PATCH 12/23] start mock modem class --- tests/Network/MockModem.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/Network/MockModem.py diff --git a/tests/Network/MockModem.py b/tests/Network/MockModem.py new file mode 100644 index 00000000..0132c883 --- /dev/null +++ b/tests/Network/MockModem.py @@ -0,0 +1,5 @@ +from Hologram.Modem import Modem + +class MockModem(Modem): + def __init__(self): + \ No newline at end of file From 8b4414f5e92ff914924a58b9d8dd8d610aa5f5b8 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 12:21:17 -0500 Subject: [PATCH 13/23] patch and use mockmodem --- tests/Cloud/test_Cloud.py | 5 ++++- tests/Cloud/test_CustomCloud.py | 6 +++++- tests/Cloud/test_HologramCloud.py | 3 +++ tests/{Network => }/MockModem.py | 0 tests/Network/test_Network.py | 2 +- 5 files changed, 13 insertions(+), 3 deletions(-) rename tests/{Network => }/MockModem.py (100%) diff --git a/tests/Cloud/test_Cloud.py b/tests/Cloud/test_Cloud.py index 5d82e97d..24d39684 100644 --- a/tests/Cloud/test_Cloud.py +++ b/tests/Cloud/test_Cloud.py @@ -15,12 +15,15 @@ from Hologram.Cloud import Cloud from Hologram.Network import Network -def mock_scan(): +from tests.MockModem import MockModem + +def mock_scan(network): return ['MockModem'] @pytest.fixture def no_modem(monkeypatch): monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) + monkeypatch.setattr(Network, '_modemHandlers', {'MockModem': MockModem}) def test_create_send(no_modem): cloud = Cloud(None, send_host = '127.0.0.1', send_port = 9999) diff --git a/tests/Cloud/test_CustomCloud.py b/tests/Cloud/test_CustomCloud.py index 1b4c814d..988a3144 100644 --- a/tests/Cloud/test_CustomCloud.py +++ b/tests/Cloud/test_CustomCloud.py @@ -15,12 +15,16 @@ from Hologram.CustomCloud import CustomCloud from Hologram.Network import Network -def mock_scan(self): +from tests.MockModem import MockModem + +def mock_scan(network): return ['MockModem'] @pytest.fixture def no_modem(monkeypatch): monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) + monkeypatch.setattr(Network, '_modemHandlers', {'MockModem': MockModem}) + def test_create_send(no_modem): customCloud = CustomCloud(None, send_host='127.0.0.1', diff --git a/tests/Cloud/test_HologramCloud.py b/tests/Cloud/test_HologramCloud.py index 95077f3c..ba23a7f9 100644 --- a/tests/Cloud/test_HologramCloud.py +++ b/tests/Cloud/test_HologramCloud.py @@ -15,6 +15,8 @@ from Hologram.HologramCloud import HologramCloud from Hologram.Network import Network +from tests.MockModem import MockModem + credentials = {'devicekey':'12345678'} def mock_scan(network): @@ -23,6 +25,7 @@ def mock_scan(network): @pytest.fixture def no_modem(monkeypatch): monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) + monkeypatch.setattr(Network, '_modemHandlers', {'MockModem': MockModem}) def test_create(no_modem): hologram = HologramCloud(credentials, enable_inbound = False) diff --git a/tests/Network/MockModem.py b/tests/MockModem.py similarity index 100% rename from tests/Network/MockModem.py rename to tests/MockModem.py diff --git a/tests/Network/test_Network.py b/tests/Network/test_Network.py index cc2abf68..de2a82fe 100644 --- a/tests/Network/test_Network.py +++ b/tests/Network/test_Network.py @@ -15,5 +15,5 @@ from Hologram.Network import Network -def test_create_network(self): +def test_create_network(): network = Network() From 8770f428118c22c5ab510b451cddb84efff0c4ae Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 12:42:50 -0500 Subject: [PATCH 14/23] Update MockModem.py --- tests/MockModem.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/MockModem.py b/tests/MockModem.py index 0132c883..17336b38 100644 --- a/tests/MockModem.py +++ b/tests/MockModem.py @@ -1,5 +1,24 @@ +import sys + +sys.path.append(".") +sys.path.append("..") from Hologram.Modem import Modem +from Hologram.Utils import ModemResult + class MockModem(Modem): def __init__(self): - \ No newline at end of file + # dont init super class + self.device_name = 'Mock Modem' + self.baud_rate = 9600 + + self.serial_port = '/dev/ttyUSB0' + self.timeout = Modem.DEFAULT_SERIAL_TIMEOUT + self.response = [] + self._at_sockets_available = False + self.urc_state = Modem.SOCKET_INIT + self.socket_identifier = 0 + self.last_read_payload_length = 0 + self.result = ModemResult.OK + self.debug_out = '' + self.in_ext = False \ No newline at end of file From 4519c01fbb0e2bc8e4f90f356aa4ea84f5a37e08 Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 13:02:53 -0500 Subject: [PATCH 15/23] add more parameters to constructor --- tests/MockModem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/MockModem.py b/tests/MockModem.py index 17336b38..3e852605 100644 --- a/tests/MockModem.py +++ b/tests/MockModem.py @@ -7,10 +7,11 @@ class MockModem(Modem): - def __init__(self): + def __init__(self, device_name=None, baud_rate='9600', + chatscript_file=None, event=None): # dont init super class self.device_name = 'Mock Modem' - self.baud_rate = 9600 + self.baud_rate = baud_rate self.serial_port = '/dev/ttyUSB0' self.timeout = Modem.DEFAULT_SERIAL_TIMEOUT From 1a9b6538ed0722758d7797a84c5fdfbb7b0bfa6c Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 13:44:38 -0500 Subject: [PATCH 16/23] fix bg96 test clean cloud file --- Hologram/CustomCloud.py | 3 +-- tests/Modem/Quectel/test_BG96.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Hologram/CustomCloud.py b/Hologram/CustomCloud.py index 8ea5b8a6..4ec5ab92 100644 --- a/Hologram/CustomCloud.py +++ b/Hologram/CustomCloud.py @@ -379,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) diff --git a/tests/Modem/Quectel/test_BG96.py b/tests/Modem/Quectel/test_BG96.py index 23981442..0067838c 100644 --- a/tests/Modem/Quectel/test_BG96.py +++ b/tests/Modem/Quectel/test_BG96.py @@ -48,7 +48,7 @@ def test_init_bg96_no_args(no_serial_port): assert(modem.timeout == 1) assert(modem.socket_identifier == 0) assert(modem.chatscript_file.endswith('/chatscripts/default-script')) - assert(modem._at_sockets_available == False) + assert(modem._at_sockets_available == True) def test_init_bg96_chatscriptfileoverride(no_serial_port): modem = BG96(chatscript_file='test-chatscript') From ba574718bdc1ac8813c134ad21b39868447da50d Mon Sep 17 00:00:00 2001 From: Dominic Amato Date: Wed, 15 Jul 2020 16:29:39 -0500 Subject: [PATCH 17/23] update test --- tests/Cloud/test_CustomCloud.py | 4 ++++ tests/MockModem.py | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/Cloud/test_CustomCloud.py b/tests/Cloud/test_CustomCloud.py index 988a3144..5801f34d 100644 --- a/tests/Cloud/test_CustomCloud.py +++ b/tests/Cloud/test_CustomCloud.py @@ -20,10 +20,14 @@ def mock_scan(network): return ['MockModem'] +def mock_disconnect(network): + return True + @pytest.fixture def no_modem(monkeypatch): monkeypatch.setattr(Network, '_scan_for_modems', mock_scan) monkeypatch.setattr(Network, '_modemHandlers', {'MockModem': MockModem}) + monkeypatch.setattr(Network, 'disconnect', mock_disconnect) def test_create_send(no_modem): diff --git a/tests/MockModem.py b/tests/MockModem.py index 3e852605..9a411816 100644 --- a/tests/MockModem.py +++ b/tests/MockModem.py @@ -22,4 +22,12 @@ def __init__(self, device_name=None, baud_rate='9600', self.last_read_payload_length = 0 self.result = ModemResult.OK self.debug_out = '' - self.in_ext = False \ No newline at end of file + self.in_ext = False + self._ppp = None + + def is_connected(self): + return True + + @property + def localIPAddress(self): + return "0.0.0.0" \ No newline at end of file From 083c83b384de5d50eef4559ea2382a44004c6130 Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Fri, 5 Mar 2021 17:01:43 -0600 Subject: [PATCH 18/23] upload SIM7000 files --- Hologram/Modem/SIMCom/SIM7000.py | 158 +++++++++++++++++++++++++++++++ Hologram/Modem/SIMCom/init.py | 0 2 files changed, 158 insertions(+) create mode 100644 Hologram/Modem/SIMCom/SIM7000.py create mode 100644 Hologram/Modem/SIMCom/init.py diff --git a/Hologram/Modem/SIMCom/SIM7000.py b/Hologram/Modem/SIMCom/SIM7000.py new file mode 100644 index 00000000..75efef41 --- /dev/null +++ b/Hologram/Modem/SIMCom/SIM7000.py @@ -0,0 +1,158 @@ +# SIM7000.py - Hologram Python SDK SIMCom SIM7000 modem interface +# +# Author: Hologram +# +# 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)) + self.urc_state = Modem.SOCKET_WRITE_STATE + + 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('+CGREG') + + # EFFECTS: Handles URC related AT command responses. + def handleURC(self, urc): + # Figure out what urcs there are to handle + 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("+CGREG", "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.set('+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' \ No newline at end of file diff --git a/Hologram/Modem/SIMCom/init.py b/Hologram/Modem/SIMCom/init.py new file mode 100644 index 00000000..e69de29b From 66434b2990dbea8f80d198faa10421b5937f3f26 Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Fri, 5 Mar 2021 17:06:29 -0600 Subject: [PATCH 19/23] check for sim7000 --- Hologram/Network.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Hologram/Network.py b/Hologram/Network.py index b38d2cfe..ec3c6dfb 100644 --- a/Hologram/Network.py +++ b/Hologram/Network.py @@ -14,6 +14,7 @@ from Hologram.Modem import Modem, DriverLoader from Hologram.Modem.Huawei import E303, MS2131, E372 from Hologram.Modem.Quectel import BG96 +from Hologram.Modem.SIMCom import SIM7000 from Hologram.Modem.UBlox import Nova_U201, NovaM import logging import time @@ -42,6 +43,7 @@ class Network: 'ms2131': MS2131.MS2131, 'e372': E372.E372, 'bg96': BG96.BG96, + 'sim7000': SIM7000.SIM7000, 'nova': Nova_U201.Nova_U201, 'novam': NovaM.NovaM, '': Modem From 040577173874b5e867b3cfced530ed0de9d4ff86 Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Fri, 5 Mar 2021 17:07:33 -0600 Subject: [PATCH 20/23] fix bug --- Hologram/Modem/SIMCom/SIM7000.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hologram/Modem/SIMCom/SIM7000.py b/Hologram/Modem/SIMCom/SIM7000.py index 75efef41..1ba321c0 100644 --- a/Hologram/Modem/SIMCom/SIM7000.py +++ b/Hologram/Modem/SIMCom/SIM7000.py @@ -120,7 +120,7 @@ def _is_pdp_context_active(self): return False ok, r = self.command('+CIPSTATUS', expected="STATE: IP START") - return ok == ModemResult.OK: + return ok == ModemResult.OK def init_serial_commands(self): self.command("E0") #echo off From e7025b740ac230b4a46eeff55a4cdb44591aec7f Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Fri, 5 Mar 2021 23:24:17 -0600 Subject: [PATCH 21/23] handle urcs, init files --- Hologram/Modem/Huawei/__init__.py | 2 ++ Hologram/Modem/Huawei/init.py | 0 Hologram/Modem/Quectel/__init__.py | 2 ++ Hologram/Modem/Quectel/init.py | 0 Hologram/Modem/SIMCom/SIM7000.py | 17 ++++++++++++++--- Hologram/Modem/SIMCom/__init__.py | 2 ++ Hologram/Modem/SIMCom/init.py | 0 Hologram/Modem/UBlox/__init__.py | 2 ++ Hologram/Modem/UBlox/init.py | 0 Hologram/Modem/__init__.py | 13 ++++++++++++- 10 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 Hologram/Modem/Huawei/__init__.py delete mode 100644 Hologram/Modem/Huawei/init.py create mode 100644 Hologram/Modem/Quectel/__init__.py delete mode 100644 Hologram/Modem/Quectel/init.py create mode 100644 Hologram/Modem/SIMCom/__init__.py delete mode 100644 Hologram/Modem/SIMCom/init.py create mode 100644 Hologram/Modem/UBlox/__init__.py delete mode 100644 Hologram/Modem/UBlox/init.py diff --git a/Hologram/Modem/Huawei/__init__.py b/Hologram/Modem/Huawei/__init__.py new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/Hologram/Modem/Huawei/__init__.py @@ -0,0 +1,2 @@ + + diff --git a/Hologram/Modem/Huawei/init.py b/Hologram/Modem/Huawei/init.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Hologram/Modem/Quectel/__init__.py b/Hologram/Modem/Quectel/__init__.py new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/Hologram/Modem/Quectel/__init__.py @@ -0,0 +1,2 @@ + + diff --git a/Hologram/Modem/Quectel/init.py b/Hologram/Modem/Quectel/init.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Hologram/Modem/SIMCom/SIM7000.py b/Hologram/Modem/SIMCom/SIM7000.py index 1ba321c0..e25b3769 100644 --- a/Hologram/Modem/SIMCom/SIM7000.py +++ b/Hologram/Modem/SIMCom/SIM7000.py @@ -70,7 +70,6 @@ def create_socket(self): def connect_socket(self, host, port): self.command('+CIPSTART', '\"TCP\",\"%s\",%d' % (host, port)) - self.urc_state = Modem.SOCKET_WRITE_STATE def close_socket(self, socket_identifier=None): ok, _ = self.command('+CIPCLOSE') @@ -110,9 +109,21 @@ def read_socket(self, socket_identifier=None, payload_length=None): def is_registered(self): return self.check_registered('+CREG') or self.check_registered('+CGREG') - # EFFECTS: Handles URC related AT command responses. + 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): - # Figure out what urcs there are to handle + 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): diff --git a/Hologram/Modem/SIMCom/__init__.py b/Hologram/Modem/SIMCom/__init__.py new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/Hologram/Modem/SIMCom/__init__.py @@ -0,0 +1,2 @@ + + diff --git a/Hologram/Modem/SIMCom/init.py b/Hologram/Modem/SIMCom/init.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Hologram/Modem/UBlox/__init__.py b/Hologram/Modem/UBlox/__init__.py new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/Hologram/Modem/UBlox/__init__.py @@ -0,0 +1,2 @@ + + diff --git a/Hologram/Modem/UBlox/init.py b/Hologram/Modem/UBlox/init.py deleted file mode 100644 index e69de29b..00000000 diff --git a/Hologram/Modem/__init__.py b/Hologram/Modem/__init__.py index c8cb4004..c38cd207 100644 --- a/Hologram/Modem/__init__.py +++ b/Hologram/Modem/__init__.py @@ -407,6 +407,12 @@ def modemwrite(self, cmd, start=False, at=False, seteq=False, read=False, self._write_to_serial_port_and_flush('\r\n') def checkURC(self, hide=False): + """ + Polls serial port until a response is returned + + :param hide: [description], defaults to False + :type hide: bool, optional + """ while(True): response = self._readline_from_serial_port(0, hide=hide) if len(response) > 0 and response.startswith('+'): @@ -415,8 +421,13 @@ def checkURC(self, hide=False): else: return - # EFFECTS: Handles URC related AT command responses. def handleURC(self, urc): + """ + Handle Unsolicited Result Codes, usually a asynch response prepended with a + + + :param urc: Urc response + :type urc: string + """ self.logger.debug("URC! %s", urc) self.logger.debug("handleURC state: %d", self.urc_state) From a40009c083afd66d7d3a59817cdc9f14546395ef Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Sat, 6 Mar 2021 14:33:25 -0600 Subject: [PATCH 22/23] remove network param from scripts --- scripts/hologram_activate.py | 2 +- scripts/hologram_modem.py | 24 ++++++++++++------------ scripts/hologram_network.py | 2 +- scripts/hologram_receive.py | 4 ++-- scripts/hologram_send.py | 6 +++--- scripts/hologram_spacebridge.py | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/hologram_activate.py b/scripts/hologram_activate.py index b8bfbee6..232273b1 100644 --- a/scripts/hologram_activate.py +++ b/scripts/hologram_activate.py @@ -33,7 +33,7 @@ def parse_hologram_activate_args(parser): # This function will call the appropriate cloud/sms handler. def run_hologram_activate(args): - hologram = HologramCloud(dict(), network='cellular') + hologram = HologramCloud(dict()) sim = hologram.network.iccid if sim is None: diff --git a/scripts/hologram_modem.py b/scripts/hologram_modem.py index efac3f2f..2d12b8ea 100644 --- a/scripts/hologram_modem.py +++ b/scripts/hologram_modem.py @@ -55,7 +55,7 @@ def run_modem_connect(args): print('Note: "hologram modem connect" is deprecated '\ 'in favor of "hologram network connect"') - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) cloud.network.disable_at_sockets_mode() res = cloud.network.connect() if res: @@ -82,7 +82,7 @@ def run_modem_disconnect(args): process.wait() def run_modem_signal(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) if args['repeat'] != 0: while True: @@ -92,7 +92,7 @@ def run_modem_signal(args): print('Signal strength: ' + str(cloud.network.signal_strength)) def run_at_command(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) cmd = '' if args['command'] is not None: cmd = args['command'].lstrip("AT") @@ -103,22 +103,22 @@ def run_at_command(args): print('Response: ' + ''.join(map(str, response)) + f'\n{result}') def run_modem_version(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) version = cloud.network.modem.version print('Modem version: ' + version) def run_modem_imei(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) imei = cloud.network.modem.imei print('IMEI: ' + imei) def run_modem_reset(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) cloud.network.modem.reset() print('Restarted modem') def run_modem_radio_off(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) res = cloud.network.modem.radio_power(False) if res: print('Modem radio disabled') @@ -126,7 +126,7 @@ def run_modem_radio_off(args): print('Failure to disable radio') def run_modem_radio_on(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) res = cloud.network.modem.radio_power(True) if res: print('Modem radio enabled') @@ -135,19 +135,19 @@ def run_modem_radio_on(args): def run_modem_sim(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) print('ICCID: ' + str(cloud.network.iccid)) def run_modem_operator(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) print('Operator: ' + str(cloud.network.operator)) def run_modem_type(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) print('Type: %s' % cloud.network.description) def run_modem_location(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud(None) location_obj = cloud.network.location if location_obj is None: print('Location: Not Available') diff --git a/scripts/hologram_network.py b/scripts/hologram_network.py index e6d737fc..1f37ad1e 100644 --- a/scripts/hologram_network.py +++ b/scripts/hologram_network.py @@ -20,7 +20,7 @@ ''' def run_network_connect(args): - cloud = CustomCloud(None, network='cellular') + cloud = CustomCloud() cloud.network.disable_at_sockets_mode() res = cloud.network.connect() if res: diff --git a/scripts/hologram_receive.py b/scripts/hologram_receive.py index b80833c4..9374847a 100644 --- a/scripts/hologram_receive.py +++ b/scripts/hologram_receive.py @@ -66,7 +66,7 @@ def run_hologram_receive(args): def run_hologram_receive_data(args): global hologram - hologram = HologramCloud(dict(), network='cellular') + hologram = HologramCloud(dict()) hologram.event.subscribe('message.received', popReceivedMessage) @@ -95,7 +95,7 @@ def run_hologram_receive_data(args): # EFFECTS: Receives SMS from the Hologram Cloud. def run_hologram_receive_sms(args): global hologram - hologram = HologramCloud(dict(), network='cellular') + hologram = HologramCloud(dict()) print ('Ready to receive sms') try: handle_polling(args['timeout'], popReceivedSMS, 1) diff --git a/scripts/hologram_send.py b/scripts/hologram_send.py index 5bfe32a8..3bd9c429 100644 --- a/scripts/hologram_send.py +++ b/scripts/hologram_send.py @@ -72,13 +72,13 @@ def parse_sms_args(parser): # EFFECTS: Parses and sends the Hologram message using TOTP Authentication def sendTOTP(args, data, is_sms=False): - hologram = HologramCloud(dict(), authentication_type='totp', network='cellular') + hologram = HologramCloud(dict(), authentication_type='totp') send_message_helper(hologram, args, is_sms=is_sms) def sendSIMOTP(args, data, is_sms=False): - hologram = HologramCloud(dict(), authentication_type='sim-otp', network='cellular') + hologram = HologramCloud(dict(), authentication_type='sim-otp') send_message_helper(hologram, args, is_sms=is_sms) # EFFECTS: Parses and sends the specified message using CSRPSK Authentication @@ -102,7 +102,7 @@ def sendPSK(args, data, is_sms=False): print(f'RESPONSE FROM CLOUD: {recv}') else: # host and port are default so use Hologram - hologram = HologramCloud(credentials, authentication_type='csrpsk', network='cellular') + hologram = HologramCloud(credentials, authentication_type='csrpsk') send_message_helper(hologram, args, is_sms=is_sms) # EFFECTS: Wraps the send message interface based on the repeat parameter. diff --git a/scripts/hologram_spacebridge.py b/scripts/hologram_spacebridge.py index 91978eae..379d0e24 100644 --- a/scripts/hologram_spacebridge.py +++ b/scripts/hologram_spacebridge.py @@ -33,7 +33,7 @@ def parse_hologram_spacebridge_args(parser): def run_hologram_spacebridge(args): global hologram - hologram = HologramCloud(dict(), network='cellular') + hologram = HologramCloud(dict()) hologram.event.subscribe('message.received', popReceivedMessage) From 92b382fccc3fcc76a0e55a7faca38bf4b3102de6 Mon Sep 17 00:00:00 2001 From: Dom Amato Date: Sat, 6 Mar 2021 14:50:56 -0600 Subject: [PATCH 23/23] change register test to LTE network --- Hologram/Modem/SIMCom/SIM7000.py | 6 +++--- Hologram/Modem/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Hologram/Modem/SIMCom/SIM7000.py b/Hologram/Modem/SIMCom/SIM7000.py index e25b3769..8c8ca816 100644 --- a/Hologram/Modem/SIMCom/SIM7000.py +++ b/Hologram/Modem/SIMCom/SIM7000.py @@ -107,7 +107,7 @@ def read_socket(self, socket_identifier=None, payload_length=None): return resp def is_registered(self): - return self.check_registered('+CREG') or self.check_registered('+CGREG') + return self.check_registered('+CREG') or self.check_registered('+CEREG') def checkURC(self, hide=False): # Not all SIMCOM urcs have a + in front @@ -147,7 +147,7 @@ def init_serial_commands(self): def set_network_registration_status(self): self.command("+CREG", "2") - self.command("+CGREG", "2") + self.command("+CEREG", "2") def _set_up_pdp_context(self): if self._is_pdp_context_active(): return True @@ -157,7 +157,7 @@ def _set_up_pdp_context(self): ok, _ = self.command('+CIPSTATUS', expected="STATE: IP INITIAL") self.set('+CSTT', '\"hologram\"') - self.set('+CIICR', timeout=30) + 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') diff --git a/Hologram/Modem/__init__.py b/Hologram/Modem/__init__.py index c38cd207..77c7fe02 100644 --- a/Hologram/Modem/__init__.py +++ b/Hologram/Modem/__init__.py @@ -709,7 +709,7 @@ def _check_registered_helper(cmd, result): response_list = r.lstrip(cmd).lstrip(': ').split(',') if len(response_list) < 2: - raise SerialError('Unable to parse registration URC response') + raise SerialError('Unable to parse registration URC response, got response: %s', response_list) regstatus = int(response_list[1]) # 1: registered home network