def sendTOTP(args, data, is_sms=False): if not args['iccid'] and ('device_id' in data): args['iccid'] = data['device_id'] if not args['imsi'] and ('private_key' in data): args['imsi'] = data['private_key'] credentials = {'device_id': args['iccid'], 'private_key': args['imsi']} hologram = HologramCloud(credentials, enable_inbound=False, authentication_type='totp', network='cellular') modem = '' # Load the ICCID and IMSI values if modem is physically attached to machine if hologram.network.isModemAttached(): modem = hologram.network.active_modem_interface hologram.credentials = {'device_id': hologram.network.iccid, 'private_key': hologram.network.imsi} hologram.initializeNetwork('cellular-' + str(modem).lower()) if (hologram.credentials['device_id'] is None) or (hologram.credentials['private_key'] is None): raise HologramError('Device id or private key not specified or cannot be pulled from modem. Please specify them or rerun the program with a provided device key') result = hologram.network.connect() if result == False: raise HologramError('Failed to connect to cell network') send_message_helper(hologram, args, is_sms=is_sms) hologram.network.disconnect()
def run_hologram_send(args): if args['message'] is None: raise HologramError('Message body cannot be empty') elif args['cloud'] and args['sms']: raise HologramError('must pick either one of cloud or sms') elif args['sms']: run_hologram_send_sms(args) else: run_hologram_send_cloud(args)
def run_hologram_send_sms(args): if args['devicekey'] is None: raise HologramError('--devicekey is required') elif args['destination'] is None: raise HologramError( '--destination missing. A destination number must be provided in order to send SMS to it' ) data = dict() # SMS can only be sent with CSRPSK auth. sendPSK(args, data, is_sms=True)
def run_hologram_send_sms(args): if args['devicekey'] is None: raise HologramError('--devicekey is required') elif args['destination'] is None: raise HologramError('--destination missing. A destination number must be provided in order to send SMS to it') data = dict() if args['authtype'] == 'totp' and not args['devicekey']: sendTOTP(args, data, is_sms=True) else: sendPSK(args, data, is_sms=True)
def _flush_used_response_from_serial_port_buffer(self, expected_response): self._serial_port_lock.writer_acquire() # LEFT SUBSTRING index = self._serial_port_buffer.find(expected_response) if index == -1: self._serial_port_lock.writer_release() raise HologramError( 'Internal SDK error: expected AT response not found') # This stores what came before it str_left = self._serial_port_buffer[:index] #print 'str_left: ' + str_left.encode('string_escape') # RIGHT SUBSTRING # Cut the substring off from the buffer by finding the 'right' position. # Find the first occurrence of AT+ since index. right = self._serial_port_buffer.find('AT', index) str_right = self._serial_port_buffer[right:] #print 'str_right: ' + str_right.encode('string_escape') self._serial_port_buffer = str_left + str_right self._serial_port_lock.writer_release()
def __init__(self, credentials, send_host='', send_port=0, receive_host='', receive_port=0, enable_inbound=False, network=''): super(CustomCloud, self).__init__(credentials, send_host=send_host, send_port=send_port, receive_host=receive_host, receive_port=receive_port, network=network) # Enforce that the send and receive configs are set before using the class. if enable_inbound and (receive_host == '' or receive_port == 0): raise HologramError('Must set receive host and port for inbound connection') self._periodic_msg_lock = threading.Lock() self._periodic_msg = None self._periodic_msg_enabled = False self._receive_buffer_lock = threading.Lock() self._receive_cv = threading.Lock() self._receive_buffer = deque() self._receive_socket = None self._accept_thread = None self.socketClose = True self._is_send_socket_open = False if enable_inbound == True: self.initializeReceiveSocket()
def sendPSK(args, data, is_sms=False): if not (args['devicekey']) and ('devicekey' in data): args['devicekey'] = data['devicekey'] if not args['devicekey']: raise HologramError('Device key not specified') credentials = {'devicekey': args['devicekey']} recv = '' if not is_sms and (args['host'] is not None or args['port'] is not None): # we're using some custom cloud customCloud = CustomCloud(None, send_host=args['host'], send_port=args['port']) recv = customCloud.sendMessage(args['message'], timeout=args['timeout']) print(f'RESPONSE FROM CLOUD: {recv}') else: # host and port are default so use Hologram hologram = HologramCloud(credentials, authentication_type='csrpsk', network='cellular') send_message_helper(hologram, args, is_sms=is_sms)
def setAuthenticationType(self, credentials, authentication_type='csrpsk'): if authentication_type not in HologramCloud._authentication_handlers: raise HologramError('Invalid authentication type: %s' % authentication_type) self.authenticationType = authentication_type self.authentication = HologramCloud._authentication_handlers[self.authenticationType](credentials)
def run_network_disconnect(args): print 'Checking for existing PPP sessions' for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name']) except: raise HologramError('Failed to check for existing PPP sessions') if 'pppd' in pinfo['name']: print 'Found existing PPP session on pid: %s' % pinfo['pid'] print 'Killing pid %s now' % pinfo['pid'] psutil.Process(pinfo['pid']).terminate()
def setAuthenticationType(self, credentials, authentication_type='csrpsk'): try: if authentication_type not in HologramCloud._authentication_handlers: raise HologramError('Invalid authentication type: %s' % authentication_type) self.authenticationType = authentication_type self.authentication = HologramCloud._authentication_handlers[ self.authenticationType](credentials) except HologramError as e: self.logger.error(repr(e)) sys.exit(1)
def run_modem_disconnect(args): print('Note: "hologram modem disconnect" is deprecated '\ 'in favor of "hologram network disconnect"') print('Checking for existing PPP sessions') for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name']) except: raise HologramError('Failed to check for existing PPP sessions') if 'pppd' in pinfo['name']: print('Found existing PPP session on pid: %s' % pinfo['pid']) print('Killing pid %s now' % pinfo['pid']) psutil.Process(pinfo['pid']).terminate()
def modem_connection_status(): #print('Checking for existing PPP sessions') for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name']) except: raise HologramError('Failed to check for existing PPP sessions') return False if 'pppd' in pinfo['name']: #print('Found existing PPP session on pid: {}'.format(pinfo['pid'])) return pinfo['pid'] # print 'Killing pid %s now' % pinfo['pid'] # psutil.Process(pinfo['pid']).terminate() #print('No PPP session running. Not Connected') return False
def sendPeriodicMessage(self, interval, message, topics=None, timeout=5): try: self._enforce_minimum_periodic_interval(interval) if not self._periodic_msg_disabled.is_set(): raise HologramError( 'Cannot have more than 1 periodic message job at once') self._periodic_msg_disabled.clear() except Exception as e: self.__enforce_network_disconnected() raise self._periodic_msg = threading.Thread( target=self._periodic_job_thread, args=[interval, self.sendMessage, message, topics, timeout]) self._periodic_msg.start()
def request_hex_nonce(self): self.open_send_socket() # build nonce request payload string nonce_request = self.authentication.buildNonceRequestPayloadString() self.logger.debug("Sending nonce request with body of length %d", len(nonce_request)) self.logger.debug('Send: %s', nonce_request) nonce = super().sendMessage(message=nonce_request, timeout=10, close_socket=False) self.logger.debug('Nonce request sent.') resultbuf_hex = binascii.b2a_hex(nonce) if resultbuf_hex is None: raise HologramError('Internal nonce error') return resultbuf_hex
def request_nonce(self): self.open_send_socket() # build nonce request payload string request = self.authentication.buildNonceRequestPayloadString() self.logger.debug("Sending nonce request with body of length %d", len(request)) self.logger.debug('Send: %s', request) self.sock.send(request) self.logger.debug('Nonce request sent.') resultbuf = binascii.b2a_hex( self.receive_send_socket(max_receive_bytes=32)) if resultbuf is None: raise HologramError('Internal nonce error') return resultbuf
def __init__(self, credentials, send_host='', send_port=0, receive_host='', receive_port=0, enable_inbound=False, network=''): super(CustomCloud, self).__init__(credentials, send_host=send_host, send_port=send_port, receive_host=receive_host, receive_port=receive_port, network=network) # Enforce that the send and receive configs are set before using the class. if enable_inbound and (receive_host == '' or receive_port == 0): raise HologramError( 'Must set receive host and port for inbound connection') self._periodic_msg = None # We start with the event set, clear it when running and then set when # shutting down. This way, the thread can wait on it and stop immediately # when the script is exiting self._periodic_msg_disabled = threading.Event() self._periodic_msg_disabled.set() self._receive_buffer_lock = threading.Lock() self._receive_cv = threading.Lock() self._receive_buffer = deque() self._receive_socket = None self._accept_thread = None self.socketClose = True self._is_send_socket_open = False if enable_inbound == True: self.initializeReceiveSocket()
def sendPeriodicMessage(self, interval, message, topics=None, timeout=5): try: self._enforce_minimum_periodic_interval(interval) self._periodic_msg_lock.acquire() if self._periodic_msg_enabled == True: raise HologramError('Cannot have more than 1 periodic message job at once') self._periodic_msg_enabled = True self._periodic_msg_lock.release() except Exception as e: self.__enforce_network_disconnected() raise self._periodic_msg = threading.Thread(target=self._periodic_job_thread, args=[interval, self.sendMessage, message, topics, timeout]) self._periodic_msg.daemon = True self._periodic_msg.start()
def _enforce_minimum_periodic_interval(self, interval): if interval < MIN_PERIODIC_INTERVAL: raise HologramError('Interval cannot be less than %d seconds.' % MIN_PERIODIC_INTERVAL)
def __enforce_receive_host_and_port(self): if self.receive_host == '' or self.receive_port == 0: raise HologramError( 'Receive host and port must be set before making this operation' )
def __enforce_send_host_and_port(self): if self.send_host == '' or self.send_port == 0: raise HologramError( 'Send host and port must be set before making this operation')
def disable_at_sockets_mode(self): raise HologramError( 'Cannot disable AT command sockets on this Modem type')
def __enforce_authentication_type_supported(self): if self.authenticationType is not 'csrpsk': raise HologramError('%s does not support SDK SMS features' % self.authenticationType)
def __enforce_valid_destination_number(self, destination_number): if not destination_number.startswith('+'): raise HologramError( 'SMS destination number must start with a \'+\' sign')
def __enforce_max_sms_length(self, message): if len(message) > MAX_SMS_LENGTH: raise HologramError('SMS cannot be more than %d characters long' % MAX_SMS_LENGTH)
def run_hologram_activate(args): hologram = HologramCloud(dict(), network='cellular') sim = hologram.network.iccid if sim is None: raise HologramError('Failed to fetch SIM number from the modem') func_args = dict() if args['apikey'] is None: (username, password) = prompt_for_username_and_password() func_args['username'] = username func_args['password'] = password else: func_args['apikey'] = args['apikey'] api = Api(**func_args) success, plans = api.getPlans() if success == False: raise HologramError('Failed to fetch plans') planIdToZonesDict = populate_valid_plans(plans) selected_plan, plan_name = prompt_for_plan(plans, planIdToZonesDict) selected_zone = prompt_for_zone(planIdToZonesDict[selected_plan]) # preview success, response = api.activateSIM(sim=sim, plan=selected_plan, zone=selected_zone, preview=True) if success == False: print('Activation verification failed: %s' % response) return elif not confirm_activation(sim, plan_name, selected_plan, selected_zone, response['total_cost']): return success, response = api.activateSIM(sim=sim, plan=selected_plan, zone=selected_zone) if success == True: print('Activating SIM... (this may take up to a few minutes)') else: print('Activation failed') return start_time = time.time() while time.time() < start_time + CHECK_LIVE_SIM_STATE_MAX_TIMEOUT: success, sim_state = api.getSIMState(sim) if sim_state == 'LIVE': break time.sleep(CHECK_LIVE_SIM_STATE_INTERVAL) if sim_state == 'LIVE': print('Activation successful!') else: print( 'SIM is still not activated. Check status in a few minutes on Hologram Dashboard (https://dashboard.hologram.io/) or contact [email protected] with any further delays' )