Пример #1
1
 def disconnectWLAN(self):
  try:
   from network import WLAN
   wlan=None
   if self.isWipy1():
    wlan=WLAN()
   else:
    wlan=WLAN(mode=WLAN.STA)
   wlan.disconnect()
  except:
   pass
Пример #2
0
def wifi_connect():
    global client, wlan

    wlan = WLAN(mode=WLAN.STA)
    wlan.disconnect()

    networks = wlan.scan()
    for net in networks:
        if net.ssid == WIFI_AP['name']:
            print('Wifi connecting...')
            wlan.connect(ssid=net.ssid, auth=(net.sec, WIFI_AP['pass']), timeout=40)
            while not wlan.isconnected():
                idle()
                sleep(1)
            break
    else:
        return False

    try:
        print('MQTT connecting...')
        client = MQTTClient(client_id="5bc8d724c03f971859b7747b", server="things.ubidots.com", user="******", password="******", port=1883)
        #client.set_callback(sub_cb)
        if client.connect() == -1:
            return False
        else:
            return True
        #client.subscribe(topic="youraccount/.../...")
    except Exception as e:
        return False
Пример #3
0
def mqtt_log(payload):
    #_AP = {'name': 'INFOTECH', 'pass': '******'}
    _AP = {'name': 'RPiAP-DP', 'pass': '******'}

    wlan = WLAN(mode=WLAN.STA)
    wlan.disconnect()

    nets = wlan.scan()
    for net in nets:
        if net.ssid == _AP['name']:
            print('Wifi connecting...')
            wlan.connect(ssid=net.ssid,
                         auth=(net.sec, _AP['pass']),
                         timeout=40)
            while not wlan.isconnected():
                idle()
                sleep(1)
            break
    else:
        return False

    try:
        print('MQTT connecting...')
        client = MQTTClient("Sipy", server="192.168.56.1", port=1883)
        #client.set_callback(sub_cb)
        if client.connect() == -1:
            return False
        print('MQTT publish')
        #client.subscribe(topic="youraccount/.../...")
        client.publish(topic="sipy/log", msg=payload)
    except MQTTException as e:
        return False
Пример #4
0
def find_wifi(testCase=None):
    wlan = WLAN(mode=WLAN.STA)
    try:
        if isinstance(testCase, Exception):
            raise testCase
        wlan.disconnect()
        nets = wlan.scan()
        for net in nets:
            if net.ssid == WIFI_AP['name']:
                #print(net, net[4])
                if not testCase == 'Not found':
                    rssi = net[4]
                    break
        else:
            rssi = -10000
        wlan.deinit()
    except Exception as e:
        return -10000

    if testCase is not None and not testCase == 'Not found':
        rssi = testCase
    if rssi >= 0:
        return -10000

    return rssi
Пример #5
0
def wifi_connect():
 while True:
  try:
   sta_if = WLAN(STA_IF)
   sta_if.active(True)
   sta_if.disconnect()
   sta_if.connect(*WIFI_SSID_PASSWORD)
   break
   time.sleep(0.5)
  except Exception as e:
   print("Error in Wlan connect: [Exception] %s: %s" % (type(e).__name__, e))
Пример #6
0
 def disconnectWLAN(self):
     try:
         from network import WLAN
         wlan = None
         if self.isWipy1():
             wlan = WLAN()
         else:
             wlan = WLAN(mode=WLAN.STA)
         wlan.disconnect()
     except:
         pass
Пример #7
0
def set_wifi(essid, pwd, timeout=60):
    console_write('[NW: STA] SET WIFI: {}'.format(essid))
    essid_found = False

    # Disable AP mode
    ap_if = WLAN(AP_IF)
    if ap_if.active():
        ap_if.active(False)
    del ap_if

    # Set STA and Connect
    sta_if = WLAN(STA_IF)
    sta_if.active(True)
    if not sta_if.isconnected():
        console_write('\t| [NW: STA] CONNECT TO NETWORK {}'.format(essid))
        # Scan wifi network - retry workaround
        for _ in range(0, 2):
            if essid in (wifispot[0].decode('utf-8')
                         for wifispot in sta_if.scan()):
                essid_found = True
                console_write(
                    '\t| - [NW: STA] ESSID WAS FOUND {}'.format(essid_found))
                break
            sleep(1)
        # Connect to the located wifi network
        if essid_found:
            # connect to network
            sta_if.connect(essid, pwd)
            # wait for connection, with timeout set
            while not sta_if.isconnected() and timeout > 0:
                console_write("\t| [NW: STA] Waiting for connection... " +
                              str(timeout) + "/60")
                timeout -= 1
                sleep(0.5)
            # Set static IP - here because some data comes from connection.
            if sta_if.isconnected() and __set_wifi_dev_static_ip(sta_if):
                sta_if.disconnect()
                del sta_if
                return set_wifi(essid, pwd)
        else:
            console_write(
                "\t| [NW: STA] Wifi network was NOT found: {}".format(essid))
            return False
        console_write("\t|\t| [NW: STA] network config: " +
                      str(sta_if.ifconfig()))
        console_write("\t|\t| [NW: STA] CONNECTED: " +
                      str(sta_if.isconnected()))
    else:
        console_write("\t| [NW: STA] ALREADY CONNECTED TO {}".format(essid))
    cfgput("devip", str(sta_if.ifconfig()[0]))
    set_uid_macaddr_hex(sta_if)
    return sta_if.isconnected()
Пример #8
0
def wifi2connect(ssid=None, password=None):
  from network import WLAN, STA_IF
  STA = WLAN(STA_IF)
  STA.active(True)
  STA.disconnect()
  wfScan=STA.scan()
  nets=[]
  [nets.append(nw[0].decode("utf-8")) for nw in wfScan]
  if ssid in nets:
    STA.connect(ssid if ssid else APSSID, password if password else APSSIDPW)
  else:
    print("\n".join(nets), end="\n"+"="*80+"\n")
    STA.active(False)
Пример #9
0
def station_connected(station: WLAN, wifiLogger: Logger):
    #TODO: remove print
    print("Connected...Testing Access...")
    wifiLogger.info("Connected...Testing Access...")
    resolved = getaddrinfo("pmtlogger.000webhostapp.com", 80)
    if resolved == []:
        #TODO: remove print
        print("No Internet Access")
        wifiLogger.debug("No Internet Access")
        station.disconnect()
    else:
        #TODO: remove print
        print("Internet Accessible")
        wifiLogger.debug("Internet Accessible")
Пример #10
0
class ConnectWIFI:
    def __init__(self):
        self.wlan = WLAN(mode=WLAN.STA)

    def connectwifi(self):
        if self.isConnected():
            print("Wifi Connected")
        else:
            self.SSID = config.wifissid
            self.PASSWORD = config.wifipassword
            timeout = time.time() + 10
            self.wlan.connect(self.SSID,
                              auth=(WLAN.WPA, self.PASSWORD),
                              channel=9)
            while not self.wlan.isconnected():
                if time.time() > timeout:
                    pycom.rgbled(config.LED_ERROR)
                    time.sleep(0.5)
                    pycom.rgbled(config.LED_ERROR)
                    machine.reset()
                print(".", end="")
                pycom.rgbled(config.LED_blink_WIFI)
                time.sleep(0.5)
                pycom.rgbled(0x000000)
                time.sleep(0.5)
                machine.idle()  # save power while waiting
            print('.........WiFi connected........')
            print("Wifi Config --> ", self.wlan.ifconfig())

    def isConnected(self):
        if self.wlan.isconnected():
            return True
        else:
            return False

    def deinit(self):
        print('Deinitializing wifi radio')
        self.wlan.deinit()

    def disconnect(self):
        print("disconnecting wifi")
        self.wlan.disconnect()

    def reconnect(self):
        if self.isConnected():
            print("wifi connected")
        else:
            print("Trying to reconnect")
            self.__init__()
            self.connectwifi()
Пример #11
0
def set_wifi(essid, pwd, timeout=60):
    console_write('[NW: STA] SET WIFI STA NW {}'.format(essid))

    # Disable AP mode
    ap_if = WLAN(AP_IF)
    if ap_if.active():
        ap_if.active(False)
    del ap_if

    # Set STA and Connect
    sta_if = WLAN(STA_IF)
    sta_if.active(True)
    # Set custom DHCP hostname
    sta_if.config(dhcp_hostname=cfgget('devfid'))
    # Check are we already connected
    if not sta_if.isconnected():
        # Multiple essid and pwd handling with retry mechanism
        essid, pwd = __select_available_wifi_nw(sta_if, essid, pwd)

        # Connect to the located wifi network
        if essid is not None:
            console_write('\t| [NW: STA] CONNECT TO NETWORK {}'.format(essid))
            # connect to network
            sta_if.connect(essid, pwd)
            # wait for connection, with timeout set
            while not sta_if.isconnected() and timeout > 0:
                console_write(
                    "\t| [NW: STA] Waiting for connection... {} sec".format(
                        timeout))
                timeout -= 1
                sleep_ms(500)
            # Set static IP - here because some data comes from connection. (subnet, etc.)
            if sta_if.isconnected() and __set_wifi_dev_static_ip(sta_if):
                sta_if.disconnect()
                del sta_if
                return set_wifi(essid, pwd)
        else:
            console_write(
                "\t| [NW: STA] Wifi network was NOT found: {}".format(essid))
            return False
        console_write("\t|\t| [NW: STA] network config: " +
                      str(sta_if.ifconfig()))
        console_write("\t|\t| [NW: STA] CONNECTED: " +
                      str(sta_if.isconnected()))
    else:
        console_write("\t| [NW: STA] ALREADY CONNECTED TO {}".format(essid))
    cfgput("devip", str(sta_if.ifconfig()[0]))
    set_dev_uid()
    return sta_if.isconnected()
Пример #12
0
    def disconnectWLAN(self):
        # disconnect wlan because it spams debug messages that disturb the monitor protocol
        try:
            from network import WLAN
            wlan = None
            if self.isWipy1():
                wlan = WLAN()
            else:
                wlan = WLAN(mode=WLAN.STA)

            wlan.disconnect()
        except:
            # if wifi disconnect fails for whatever reason, let it continue to sync
            # often this is the 'OSError: the requested oparation is not possible' thrown by the wlan.disconnect line
            pass
Пример #13
0
def connect_wifi_sdk(ssid, pw):
    from network import WLAN
    from network import STA_IF
    import machine

    wlan = WLAN(STA_IF)
    nets = wlan.scan()
    if (wlan.isconnected()):
        wlan.disconnect()
    wlan.connect(ssid, pw)
    while not wlan.isconnected():
        machine.idle()  # save power while waiting
        print('WLAN connection succeeded!')
        break
    print("connected:", wlan.ifconfig())
Пример #14
0
    def disconnectWLAN(self):
        # disconnect wlan because it spams debug messages that disturb the monitor protocol
        try:
            from network import WLAN
            wlan = None
            if self.isWipy1():
                wlan = WLAN()
            else:
                wlan = WLAN(mode=WLAN.STA)

            wlan.disconnect()
        except:
            # if wifi disconnect fails for whatever reason, let it continue to sync
            # often this is the 'OSError: the requested oparation is not possible' thrown by the wlan.disconnect line
            pass
Пример #15
0
def wlan_scan():
    while (True):
        global oled
        wlan = WLAN(STA_IF)
        wlan.active(True)
        if wlan.isconnected():
            wlan.disconnect()
        list = wlan.scan()
        oled.fill(0)
        if not all(list):
            oled.text('Searching networks.', 0, 0)
            oled.show()
        else:
            oled.text('Networks found: ', 0, 0)
            oled.show()
        for i in range(len(list)):
            oled.text(list[i][0].decode(), 0, (i * 8) + 8)
            oled.show()
        sleep(5)
Пример #16
0
class WIFI(Connection):
    def __init__(self, networks: dict):
        from network import WLAN
        self.wlan = WLAN(mode=WLAN.STA)
        self.networks = networks

    def connect(self):
        if self.wlan.isconnected():
            return

        for _ in range(4):
            nets = self.wlan.scan()
            print("\tsearching for wifi networks...")
            for net in nets:
                if net.ssid in self.networks:
                    ssid = net.ssid
                    password = self.networks[ssid]
                    print('\twifi network ' + ssid + ' found, connecting ...')
                    self.wlan.connect(ssid,
                                      auth=(net.sec, password),
                                      timeout=5000)
                    while not self.wlan.isconnected():
                        machine.idle()  # save power while waiting
                    print('\twifi network connected')
                    print('\tIP address: {}'.format(self.wlan.ifconfig()))
                    print('\tMAC address: {}\n'.format(
                        hexlify(machine.unique_id(), ':').decode().upper()))
                    return
            print("!! no usable networks found, trying again in 30s")
            print("!! available networks:")
            print("!! " + repr([net.ssid for net in nets]))
            machine.idle()
            time.sleep(30)

        raise OSError("!! unable to connect to WIFI network.")

    def isconnected(self) -> bool:
        return self.wlan.isconnected()

    def disconnect(self):
        if self.wlan.isconnected():
            self.wlan.disconnect()
Пример #17
0
def ConnectWLAN(onOff):
    wlan = WLAN()

    # Connect to wlan
    if onOff:
        wlan.antenna(wlanAntType)

        if machine.reset_cause() != machine.SOFT_RESET:
            wlan.init(mode=WLAN.STA)
            wlan.ifconfig(config=(ip, subnet, router, dns))

        if not wlan.isconnected():
            wlan.connect(wlanName, auth=(wlanType, wlanPass), timeout=5000)

            while not wlan.isconnected():
                machine.idle()

    # Disconnect from wlan
    else:
        wlan.disconnect()

        while wlan.isconnected():
            machine.idle()
Пример #18
0
class NanoGateway:
    """
    Nano gateway class, set up by default for use with TTN, but can be configured
    for any other network supporting the Semtech Packet Forwarder.

    Only required configuration is wifi_ssid and wifi_password which are used for
    connecting to the Internet.
    """

    PROTOCOL_VERSION = const(2)

    PUSH_DATA = const(0)
    PUSH_ACK = const(1)
    PULL_DATA = const(2)
    PULL_ACK = const(4)
    PULL_RESP = const(3)

    TX_ERR_NONE = 'NONE'
    TX_ERR_TOO_LATE = 'TOO_LATE'
    TX_ERR_TOO_EARLY = 'TOO_EARLY'
    TX_ERR_COLLISION_PACKET = 'COLLISION_PACKET'
    TX_ERR_COLLISION_BEACON = 'COLLISION_BEACON'
    TX_ERR_TX_FREQ = 'TX_FREQ'
    TX_ERR_TX_POWER = 'TX_POWER'
    TX_ERR_GPS_UNLOCKED = 'GPS_UNLOCKED'

    UDP_THREAD_CYCLE_MS = const(10)

    STAT_PK = {
        'stat': {
            'time': '',
            'lati': 0,
            'long': 0,
            'alti': 0,
            'rxnb': 0,
            'rxok': 0,
            'rxfw': 0,
            'ackr': 100.0,
            'dwnb': 0,
            'txnb': 0
        }
    }

    RX_PK = {
        'rxpk': [{
            'time': '',
            'tmst': 0,
            'chan': 0,
            'rfch': 0,
            'freq': 0,
            'stat': 1,
            'modu': 'LORA',
            'datr': '',
            'codr': '4/5',
            'rssi': 0,
            'lsnr': 0,
            'size': 0,
            'data': ''
        }]
    }

    TX_ACK_PK = {'txpk_ack': {'error': ''}}

    def __init__(self,
                 wifi_ssid,
                 wifi_password,
                 gateway_id=None,
                 server='router.eu.thethings.network',
                 port=1700,
                 frequency=868100000,
                 datarate='SF7BW125',
                 ntp_server='pool.ntp.org',
                 ntp_period=3600):
        # If unset, set the Gateway ID to be the first 3 bytes
        # of MAC address + 'FFFE' + last 3 bytes of MAC address
        if gateway_id is None:
            gateway_id = ubinascii.hexlify(machine.unique_id()).upper()
            gateway_id = gateway_id[:6] + 'FFFE' + gateway_id[6:12]
        self.gateway_id = gateway_id

        self.server = server
        self.port = port

        self.frequency = frequency
        self.datarate = datarate

        self.wifi_ssid = wifi_ssid
        self.wifi_password = wifi_password

        self.ntp_server = ntp_server
        self.ntp_period = ntp_period

        self.server_ip = None

        self.rxnb = 0
        self.rxok = 0
        self.rxfw = 0
        self.dwnb = 0
        self.txnb = 0

        self.sf = self._dr_to_sf(self.datarate)
        self.bw = self._dr_to_bw(self.datarate)

        self.stat_alarm = None
        self.pull_alarm = None
        self.uplink_alarm = None

        self.wlan = None
        self.sock = None
        self.udp_stop = False
        self.udp_lock = _thread.allocate_lock()

        self.lora = None
        self.lora_sock = None

        self.rtc = machine.RTC()

    def start(self):
        """
        Starts the nano gateway.
        """

        self.log('Starting nano gateway with id {}', self.gateway_id)

        # Change WiFi to STA mode and connect
        self.wlan = WLAN(mode=WLAN.STA)
        self._connect_to_wifi()

        # Get a time sync
        self.log('Syncing time with {} ...', self.ntp_server)
        self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
        while not self.rtc.synced():
            utime.sleep_ms(50)
        self.log('RTC NTP sync complete')

        # Get the server IP and create an UDP socket
        self.server_ip = usocket.getaddrinfo(self.server, self.port)[0][-1]
        self.log('Opening UDP socket to {} ({}) port {}...', self.server,
                 self.server_ip[0], self.server_ip[1])
        self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM,
                                   usocket.IPPROTO_UDP)
        self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
        self.sock.setblocking(False)

        # Push the first time stat immediately
        self._push_data(self._make_stat_packet())

        # Create the alarms
        self.stat_alarm = machine.Timer.Alarm(
            handler=lambda t: self._push_data(self._make_stat_packet()),
            s=60,
            periodic=True)
        self.pull_alarm = machine.Timer.Alarm(
            handler=lambda u: self._pull_data(), s=25, periodic=True)

        # Start the UDP receive thread
        self.udp_stop = False
        _thread.start_new_thread(self._udp_thread, ())

        # Initialize the LoRa radio in LORA mode
        self.log('Setting up LoRa socket on {:.1f} Mhz using {}',
                 self._freq_to_float(self.frequency), self.datarate)
        self.lora = LoRa(mode=LoRa.LORA,
                         frequency=self.frequency,
                         bandwidth=self.bw,
                         sf=self.sf,
                         preamble=8,
                         coding_rate=LoRa.CODING_4_5,
                         tx_iq=True)

        # Create a raw LoRa socket
        self.lora_sock = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW)
        self.lora_sock.setblocking(False)

        self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT
                                    | LoRa.TX_PACKET_EVENT),
                           handler=self._lora_cb)
        self.log('Nano gateway online')

    def stop(self):
        """
        Stops the nano gateway.
        """

        self.log('Stopping...')

        # Send the LoRa radio to sleep
        self.lora.callback(trigger=None, handler=None)
        self.lora.power_mode(LoRa.SLEEP)

        # Stop the NTP sync
        self.rtc.ntp_sync(None)

        # Cancel all the alarms
        self.stat_alarm.cancel()
        self.pull_alarm.cancel()

        # Signal the UDP thread to stop
        self.udp_stop = True
        while self.udp_stop:
            utime.sleep_ms(50)

        # Disable WLAN
        self.wlan.disconnect()
        self.wlan.deinit()

    def _connect_to_wifi(self):
        self.wlan.connect(self.wifi_ssid, auth=(None, self.wifi_password))
        while not self.wlan.isconnected():
            utime.sleep_ms(50)
        self.log('WiFi connected: {}', self.wifi_ssid)

    def _dr_to_sf(self, dr):
        sf = dr[2:4]
        if sf[1] not in '0123456789':
            sf = sf[:1]
        return int(sf)

    def _dr_to_bw(self, dr):
        bw = dr[-5:]
        if bw == 'BW125':
            return LoRa.BW_125KHZ
        elif bw == 'BW250':
            return LoRa.BW_250KHZ
        else:
            return LoRa.BW_500KHZ

    def _sf_bw_to_dr(self, sf, bw):
        dr = 'SF' + str(sf)
        if bw == LoRa.BW_125KHZ:
            return dr + 'BW125'
        elif bw == LoRa.BW_250KHZ:
            return dr + 'BW250'
        else:
            return dr + 'BW500'

    def _lora_cb(self, lora):
        """
        Event listener for LoRa radio events.
        """

        events = lora.events()
        if events & LoRa.RX_PACKET_EVENT:
            self.rxnb += 1
            self.rxok += 1
            rx_data = self.lora_sock.recv(256)
            stats = lora.stats()
            packet = self._make_node_packet(rx_data, self.rtc.now(),
                                            stats.rx_timestamp, stats.sfrx,
                                            self.bw, stats.rssi, stats.snr)
            self.log('Received packet: {}', packet)
            self._push_data(packet)
            self.rxfw += 1
        if events & LoRa.TX_PACKET_EVENT:
            self.log('Re-initing LoRa radio after transmission')
            self.txnb += 1
            lora.init(mode=LoRa.LORA,
                      frequency=self.frequency,
                      bandwidth=self.bw,
                      sf=self.sf,
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True)

    def _freq_to_float(self, frequency):
        """
        MicroPython has some inprecision when doing large float division.

        To counter this, this method first does integer division until we
        reach the decimal breaking point. This doesn't completely elimate
        the issue in all cases, but it does help for a number of commonly
        used frequencies.
        """

        divider = 6
        while divider > 0 and frequency % 10 == 0:
            frequency = frequency // 10
            divider -= 1
        if divider > 0:
            frequency = frequency / (10**divider)
        return frequency

    def _make_stat_packet(self):
        now = self.rtc.now()
        self.STAT_PK['stat']['time'] = '%d-%02d-%02d %02d:%02d:%02d GMT' % (
            now[0], now[1], now[2], now[3], now[4], now[5])
        self.STAT_PK['stat']['rxnb'] = self.rxnb
        self.STAT_PK['stat']['rxok'] = self.rxok
        self.STAT_PK['stat']['rxfw'] = self.rxfw
        self.STAT_PK['stat']['dwnb'] = self.dwnb
        self.STAT_PK['stat']['txnb'] = self.txnb
        return ujson.dumps(self.STAT_PK)

    def _make_node_packet(self, rx_data, rx_time, tmst, sf, bw, rssi, snr):
        self.RX_PK['rxpk'][0]['time'] = '%d-%02d-%02dT%02d:%02d:%02d.%dZ' % (
            rx_time[0], rx_time[1], rx_time[2], rx_time[3], rx_time[4],
            rx_time[5], rx_time[6])
        self.RX_PK['rxpk'][0]['tmst'] = tmst
        self.RX_PK['rxpk'][0]['freq'] = self._freq_to_float(self.frequency)
        self.RX_PK['rxpk'][0]['datr'] = self._sf_bw_to_dr(sf, bw)
        self.RX_PK['rxpk'][0]['rssi'] = rssi
        self.RX_PK['rxpk'][0]['lsnr'] = float(snr)
        self.RX_PK['rxpk'][0]['data'] = ubinascii.b2a_base64(rx_data)[:-1]
        self.RX_PK['rxpk'][0]['size'] = len(rx_data)
        return ujson.dumps(self.RX_PK)

    def _push_data(self, data):
        token = uos.urandom(2)
        packet = bytes([self.PROTOCOL_VERSION]) + token + bytes(
            [self.PUSH_DATA]) + ubinascii.unhexlify(self.gateway_id) + data
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except BaseException as ex:
                self.log('Failed to push uplink packet to server: {}', ex)

    def _pull_data(self):
        token = uos.urandom(2)
        packet = bytes([self.PROTOCOL_VERSION]) + token + bytes(
            [self.PULL_DATA]) + ubinascii.unhexlify(self.gateway_id)
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except BaseException as ex:
                self.log('Failed to pull downlink packets from server: {}', ex)

    def _ack_pull_rsp(self, token, error):
        self.TX_ACK_PK['txpk_ack']['error'] = error
        resp = ujson.dumps(self.TX_ACK_PK)
        packet = bytes([self.PROTOCOL_VERSION]) + token + bytes(
            [self.PULL_ACK]) + ubinascii.unhexlify(self.gateway_id) + resp
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except BaseException as ex:
                self.log('PULL RSP ACK exception: {}', ex)

    def _send_down_link(self, data, tmst, datarate, frequency):
        """
        Transmits a downlink message over LoRa.
        """

        self.lora.init(mode=LoRa.LORA,
                       frequency=frequency,
                       bandwidth=self._dr_to_bw(datarate),
                       sf=self._dr_to_sf(datarate),
                       preamble=8,
                       coding_rate=LoRa.CODING_4_5,
                       tx_iq=True)
        while utime.ticks_us() < tmst:
            pass
        self.lora_sock.send(data)
        self.log(
            'Sent downlink packet scheduled for {:.3f}, at {:.1f} Mhz using {}: {}',
            tmst / 1000000, self._freq_to_float(frequency), datarate, data)

    def _udp_thread(self):
        """
        UDP thread, reads data from the server and handles it.
        """

        while not self.udp_stop:
            try:
                data, src = self.sock.recvfrom(1024)
                _token = data[1:3]
                _type = data[3]
                if _type == self.PUSH_ACK:
                    self.log('Push ack')
                elif _type == self.PULL_ACK:
                    self.log('Pull ack')
                elif _type == self.PULL_RESP:
                    self.dwnb += 1
                    ack_error = self.TX_ERR_NONE
                    tx_pk = ujson.loads(data[4:])
                    tmst = tx_pk['txpk']['tmst']
                    t_us = tmst - utime.ticks_us() - 12500
                    if t_us < 0:
                        t_us += 0xFFFFFFFF
                    if t_us < 20000000:
                        self.uplink_alarm = machine.Timer.Alarm(
                            handler=lambda x: self._send_down_link(
                                ubinascii.a2b_base64(tx_pk['txpk']['data']),
                                tx_pk['txpk']['tmst'] - 50, tx_pk['txpk'][
                                    'datr'],
                                int(tx_pk['txpk']['freq'] * 1000000)),
                            us=t_us)
                    else:
                        ack_error = self.TX_ERR_TOO_LATE
                        self.log('Downlink timestamp error!, t_us: {}', t_us)
                    self._ack_pull_rsp(_token, ack_error)
                    self.log('Pull rsp')
                else:
                    self.log('Unknown message type from server: {}', _type)
            except usocket.timeout:
                pass
            except OSError as ex:
                if ex.errno != errno.EAGAIN:
                    self.log('UDP recv OSError Exception: {}', ex)
            except BaseException as ex:
                self.log('UDP recv Exception: {}', ex)

            # Wait before trying to receive again
            utime.sleep_ms(self.UDP_THREAD_CYCLE_MS)

        self.sock.close()
        self.udp_stop = False
        self.log('UDP thread stopped')

    def log(self, message, *args):
        """
        Prints a log message to the stdout.
        """

        print('[{:>10.3f}] {}'.format(utime.ticks_ms() / 1000,
                                      str(message).format(*args)))
Пример #19
0
class WifiManager:
    def __init__(self, jsonfile):
        # Load configuration from config JSON file.
        # wificonfig.json contans the network settings
        # STATIC_IP is 'None' or empty string -> use dynamic IP
        self._config = self.readjson(jsonfile)

        # create network in STAtion mode
        # pycom: device always starts up in AP-mode
        self._wlan = WLAN(mode=WLAN.STA)
        if USE_DEBUG:
            print('WifiManager::WLAN mode:',
                  self._wlan.mode())  # pycom: 1=STA, 2=AP)

    def readjson(self, jsonfile):
        """readjson(file) - returns the contents of file in JSON-format"""
        with open(jsonfile, 'r') as infile:
            config = json.load(infile)
        if USE_DEBUG:
            print('WifiManager::JSON settings: {}'.format(config))
        return config

    # pycom connect
    def connect(self):
        """connect() - connects device according to network parameters in JSON-file."""
        self._wlan = WLAN()  # get current object, without changing the mode

        # skip connecting, when a soft-reset is performed
        if machine.reset_cause() != machine.SOFT_RESET:
            self._wlan.init(mode=WLAN.STA)
            # configuration below MUST match your home router settings!!
            # IP, Subnet, Gateway, DNS
            if self._config['STATIC_IP'] is None:
                if USE_DEBUG:
                    print('WifiManager::Static IP configuration for SSID: ',
                          self._config['SSID'])
                self._wlan.ifconfig(config=(self._config['STATIC_IP'],
                                            self._config['MASKER'],
                                            self._config['GATEWAY_IP'],
                                            self._config['DNS']))
            else:
                if USE_DEBUG:
                    print('WifiManager::Dynamic IP configuration for SSID: ',
                          self._config['SSID'])
                pass

            # connect to Wifi
            if USE_DEBUG:
                print('WifiManager::isconnected:', self._wlan.isconnected())

            if not self._wlan.isconnected():
                if USE_DEBUG:
                    print(
                        "WifiManager::start '{0}' to connect to '{1}' with IP '{2}'"
                        .format(self._config['IDENTITY'], self._config['SSID'],
                                self._config['STATIC_IP']))

                # change the line below to match your network ssid, security and password
                self._wlan.connect(self._config['SSID'],
                                   auth=(WLAN.WPA2, self._config['PASSWRD']),
                                   timeout=5000)
                while not self._wlan.isconnected():
                    machine.idle()  # save power while waiting

        # connected, return network config
        return self._wlan.ifconfig()

    # wrapper for disconnecting network
    def disconnect(self):
        """disconnect() - de-activate network interface, but leaves Wifi radio on"""
        self._wlan.disconnect(
        )  # pycom - disconnect from Wifi, but leave Wif radio on.
        if USE_DEBUG:
            print('WifiManager::Wifi disconnected')

    # wrapper for disabling Wifi radio
    def deinit(self):
        """deinit() - disable Wifi radio"""
        self._wlan.deint()  # pycom
        if USE_DEBUG:
            print('WifiManager::Wifi radio off')

    # wrapper for network scan
    def scan(self):
        """scan() - Performs a network scan and returns a list
        of named tuples with (ssid, bssid, sec, channel, rssi)
        """
        return self._wlan.scan()

    # wrapper for wlan.isconnected()
    @property
    def isconnected(self):
        """isconnected() - returns if connected to Wifi (True)
        or not (False)"""
        return self._wlan.isconnected()

    def print_config(self):
        """print_config() - print config data on screen."""
        for key in self._config.keys():
            print('[{0}] = {1}'.format(key, self._config[key]))

    def change_access(self, user=None, passwrd=None):
        """change_access - change password for telnet and ftp access"""
        if (user is None) or (passwrd is None):
            print('WifiManager:: username and password must be specified')
            return

        server = Server()  # from network
        # disable the server
        server.deinit()
        # enable the server again with new credentials
        # for example: remote access, ftp and telnet, not USB
        server.init(login=(user, passwrd), timeout=600)
        if USE_DEBUG:
            print('WifiManager::password {} is changed...'.format(user))

    @property
    def __config(self):
        """returns config tuple"""
        return self._config

    @property
    def mac(self):
        """returns MAC-address of device"""
        mac = hexlify(self._wlan.mac(), ':').decode()  # pycom
        # return (mac) # lower case
        return mac.upper()
Пример #20
0
        print(err)
        LOGFILE = ("{}-{:04d}{:02d}{:02d}.{}".format(LOGNAME, t[0], t[1], t[2], LOGEXT))
        f = open(LOGFILE, 'a')
        f.write('%s\n' %(err))
        f.close()
        #print(".", end = "")
        sleep_ms(500)
    if retry==MQTTRETRY:
        LED2.value(0)
        err = ("{:04d}{:02d}{:02d}-{:02d}{:02d}{:02d} failed MQTT connect, will reboot".format(t[0], t[1], t[2], t[4], t[5], t[6]))
        print(err)
        f = open(LOGFILE, 'a')
        f.write('%s\n' %(err))
        f.close()
        print('disconnection station...', end='')
        station.disconnect()
        sleep_ms(10)
        print('station connected:', station.isconnected())
        print('going to deepsleep')
        deepsleep(100)
LED2.value(0)

### status MQTT msg ###
'''
LED2.value(1)
t=rtc.datetime()
sta = ("{:04d}{:02d}{:02d}-{:02d}{:02d}{:02d} connected to MQTT socket".format(t[0], t[1], t[2], t[4], t[5], t[6]))
print(sta)
client.publish(TOPICSTA, sta, qos=QOSSTA)
LED2.value(0)
'''
Пример #21
0
class WiFi:
    RECONNECT_TIMEOUT = 10

    def __init__(self, config, verbose=0):
        self.verbose = verbose
        self.config = config
        self.__connecting = False
        self.connect_start = None
        self.station = WLAN(STA_IF)

    def __repr__(self):
        return '<WiFi: {}, {} at {:x}>'.format(self.station.config('essid'),
                                               self.station.ifconfig(),
                                               id(self))

    def device_id(self):
        import ubinascii
        return ubinascii.hexlify(self.station.config('mac'),
                                 ':').decode().upper()

    def connecting(self):
        return self.__connecting

    def connected(self):
        return self.station.isconnected()

    def connect(self):
        if self.__connecting:
            if self.station.isconnected():
                self.__connecting = False
                self.connect_start = None
            elif (time() - self.connect_start) > self.RECONNECT_TIMEOUT:
                # self.station.active(False)
                self.__connecting = False
                self.connect_start = time()
                if self.verbose:
                    print('-> ' 'Connect ' 'timeout')
        elif self.station.isconnected() is False:
            if self.connect_start is None or (
                    time() - self.connect_start) > self.RECONNECT_TIMEOUT:
                if self.verbose:
                    if self.connect_start is None:
                        print('-> ' 'Reconnect ' 'timer started')
                    else:
                        print('-> ' 'Reconnect ' 'timeout')
                self.connect_start = time()
            else:
                return False
            self.station.active(True)
            ssid, password = self.scan()
            if self.verbose:
                print('[{}] [{}]'.format(ssid, password))
            if ssid:
                self.station.connect(ssid, password)
                sleep(1)
                self.__connecting = True
            return True
        return False

    def disconnect(self):
        self.station.disconnect()

    def scan(self):
        ssid, password = None, None
        ap_scan = self.station.scan()
        ap_list = []
        for ap in ap_scan:
            for ssid_mask, password in self.config['wifi']:
                mask = '^{}$'.format(ssid_mask)
                if search(mask, ap[0]):
                    ap_list.append((ap[3], ap[0], password))
        ap_list.sort(reverse=True)
        if self.verbose:
            for ap in ap_list:
                print(ap)
        if len(ap_list):
            ssid, password = ap_list[0][1], ap_list[0][2]
        return ssid, password
Пример #22
0
wifi.antenna(WLAN.INT_ANT)
wifi.mode(WLAN.STA)
print(wifi.mode() == WLAN.STA)
wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=10000)
wait_for_connection(wifi)

wifi.ifconfig(config='dhcp')
wait_for_connection(wifi)
print('0.0.0.0' not in wifi.ifconfig())
wifi.ifconfig(0, ('192.168.178.109', '255.255.255.0', '192.168.178.1', '8.8.8.8'))
wait_for_connection(wifi)
print(wifi.ifconfig(0) == ('192.168.178.109', '255.255.255.0', '192.168.178.1', '8.8.8.8'))
wait_for_connection(wifi)

print(wifi.isconnected() == True)
wifi.disconnect()
print(wifi.isconnected() == False)

t0 = time.ticks_ms()
wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=0)
print(time.ticks_ms() - t0 < 500)

wifi.disconnect()
print(wifi.isconnected() == False)

# test init again
wifi.init(WLAN.AP, ssid='www.wipy.io', auth=None, channel=5, antenna=WLAN.INT_ANT)

print(len(wifi.mac()) == 6)

# next ones MUST raise
Пример #23
0
class Wifi:
    """
    A module for controlling the Wifi radio of the device. The methods in this
    module are permissive. For instance, if the Wifi radio is not yet
    activated, it will automatically be turned on when connecting to an access
    point.

    In order to save battery, the Wifi radio should be turned off through a
    call to `deactivate()` whenever possible.

    Since this module is shared by multiple threads, there is a potential risk
    in one thread turning off the Wifi radio when it is used by another. Thus,
    whenever a thread uses the Wifi radio, it should inform the wifi module
    first. It is also vital to inform the Wifi module when done using the Wifi
    radio - otherwise it may never be possile to deactivate it again. Other
    threads are not able to disable Wifi when it is in use. However, threads
    are free to enable Wifi at any time.

    The Wifi locking mechanism used in this module is a simple readers-writer
    lock using the Raynal method. Thus, the technique prefers users of the Wifi
    radio.
    """

    def __init__(self, ssid: str, pw: str):
        self._station = WLAN(STA_IF)
        self._ssid = ssid
        self._pw = pw

        # Readers-writer lock for activation/deactivation
        self.__readers_lock = _thread.allocate_lock()
        self.__global_lock = _thread.allocate_lock()
        self.__clients = []

    def activate(self):
        """Turn on the Wifi radio if it is off."""
        if not self._station.active():
            self._station.active(True)

    def deactivate(self, blocking=True):
        """
        Turn off the Wifi radio. This will also disconnect from the access
        point, if connected. If the Wifi radio is used by other threads, this
        method will block until Wifi can be deactivated. Alternatively, the the
        client can pass `False` to the `blocking` parameter to return
        immediately if the radio is used by others. This is useful if
        deactivation of the radio is not a hard requirement, but simply a hint.
        """
        if self.__global_lock.acquire(1 if blocking else 0):
            try:
                if self._station.isconnected():
                    self.__disconnect()
                if self._station.active():
                    self._station.active(False)
            finally:
                self.__global_lock.release()

    def connect(self) -> bool:
        """
        Connect to the access point if not already connected. This method will
        also ativate the Wifi radio if it is not currently on. However, if the
        method fails, it will not turn off the radio again.
        """
        self.activate()

        if self._station.isconnected():
            return True
        
        self._station.connect(self._ssid, self._pw)
        utime.sleep(2)  # Allow the radio some time to connect
        if self._station.isconnected():
            return True
        
        self._station.disconnect()
        return False

    def is_connected(self):
        """Check if currently connected to the access point."""
        return self._station.isconnected()

    def disconnect(self, blocking=True):
        """
        Disconnect from the access point if currently connected. If the Wifi
        radio is currently used by other threads, this method will block until
        it is possible to disconnect. Alternatively, the the client can pass
        `False` to the `blocking` parameter to return immediately if the radio 
        is used by others. This is useful if deactivation of the radio is not a
        hard requirement, but simply a hint.
        """
        if self.__global_lock.acquire(1 if blocking else 0):
            try:
                self.__disconnect()
            finally:
                self.__global_lock.release()
    
    def __disconnect(self):
        if self.is_connected():
            self._station.disconnect()
    
    def scan(self):
        """
        Scan for nearby access points. If the Wifi radio is not on, it will
        automatically be enabled.
        """
        self.activate()
        for _ in range(3):
            try:
                return self._station.scan()
            except RuntimeError:
                utime.sleep(1)  # Give radio time to turn on

    def acquire(self):
        """
        Inform the Wifi module that a thread wishes to use the Wifi radio. It
        is vital to match each call to this method with a similar call to
        `release()`. Each thread will be registered only once, regardless of
        how many times it calls this method.
        """
        self.__readers_lock.acquire()
        try:
            tid = _thread.get_ident()
            if not tid in self.__clients:
                self.__clients.append(tid)
                self.__global_lock.acquire(0)
        finally:
            self.__readers_lock.release()

    def release(self):
        """
        Inform the Wifi module that a client is done using the Wifi radio. If
        the calling thread has not been registered by a previous call to
        `acquire()`, then calling this method has no effect. Furthermore, it
        has no effect if a thread calls this method multiple times in
        succession.
        """
        self.__readers_lock.acquire()
        try:
            tid = _thread.get_ident()
            if tid in self.__clients:
                self.__clients.remove(tid)
                if len(self.__clients) == 0 and self.__global_lock.locked():
                    self.__global_lock.release()
        finally:
            self.__readers_lock.release()
Пример #24
0
class WlanThreaded:
    TIMEOUT = 5000
    def __init__(self, ssid:str='', key:str=''):
        self._ssid = ssid
        self._key = key
        self._wlan = WLAN(mode=WLAN.STA)
        self._running = False
        _thread.start_new_thread(self._connect, ())

    def is_connected(self):
        return self._wlan.isconnected()

    def print_wlan(self):
        print(self._wlan.ifconfig())

    def stop(self):
        self._running = False

    def _connect(self):
        global color
        self._running = True
        try:
            while self._running:
                color = 0x300000
                print('Connecting to <%s>' % (self._ssid))
                self._wlan.scan()
                timer = Timer.Chrono()
                timer.start()
                self._wlan.connect(ssid=self._ssid, auth=(WLAN.WPA2, self._key), timeout=WlanThreaded.TIMEOUT)
                while not self._wlan.isconnected():
                    if not self._running:
                        break
                    duration = timer.read_ms()
                    if duration > WlanThreaded.TIMEOUT:
                        break
                    sleep(0.1)
                if self._running and self._wlan.isconnected():
                    self.print_wlan()
                    self._start_server()
        except KeyboardInterrupt:
            pass
        self._running = False
        color = 0xff0000
        print('Disconnecting from <%s>' % (self._ssid))
        while True:
            try:
                self._wlan.disconnect()
                break
            except KeyboardInterrupt:
                pass
        color = 0x000000
        print('Shutting down')

    def _start_server(self):
        global color
        color = 0x300030
        print('Starting server')
        pyServer = PyServer(10000)
        pyServer.listen(self)
        color = 0x300030
        print('Stopped server')
Пример #25
0
class Wifi(ConfigOp):
    def __init__(self, hostname, pin=2):
        self.__wlan = None
        self.__timeout = DEFAULT_TMOUT
        self.__led = Relay(pin)
        self.is_ok = False
        self.gw = None
        self.ip = None
        self.dns = None
        ConfigOp.__init__(self, 'wifi', CONFIG_NAME)
        self.add_command(self.__get_info, GET)
        self.add_command(self.__reconnect, SET, 'reconnect')
        self.__hostname = hostname

    def is_connected(self):
        return self.__wlan != None and self.__wlan.isconnected()

    async def __get_info(self, _):
        v = self.get_info()
        await sleep(0)
        return result(200, None, v)

    async def __reconnect(self, _):
        delayed_task(5000, self.async_connect, (True), True)
        return result(200, None, RECONNECT_WIFI)

    async def __reload_config(self):  # NOSONAR
        return await self.__reconnect(None)

    def get_info(self):
        return {
            "mac": MAC,
            "connected": self.is_connected(),
            "connection tested": self.is_ok,
            "hostname": self.__hostname,
            "ip": self.ip,
            "gw": self.gw,
            "dns": self.dns
        }

    def check_wifi_config(self):
        self.load()
        return not (self.__config is None or is_str_empty(self.__config[SSID])
                    or is_str_empty(self.__config[PASSWORD]))

    def disconnect(self):
        if self.__wlan is not None and self.__wlan.isconnected():
            self.__wlan.disconnect()
            self.__wlan.active(False)

    async def async_connect(self, force_rec=False):
        if self.__wlan is not None and self.__wlan.isconnected():
            if force_rec:
                self.disconnect()
                return await self.__async_connect()
            return True
        return await self.__async_connect()

    async def __async_connect(self):
        self.__connect_init()
        return await self.__async_connect_finish()

    async def __async_connect_finish(self):
        start_time = time()  # Check time
        while not self.__wlan.isconnected():
            await sleep_ms(DEFAULT_300)
            self.__led.on()
            await sleep_ms(DEFAULT_300)
            self.__led.off()
            if time() - start_time > self.__timeout:
                log.error("Wifi connection timeout: %d", self.__timeout)
                break
        return self.__set_properties()

    def __connect_init(self):
        self.check_wifi_config()
        if self.__config is None:
            log.error("Wifi config is None")
            return
        log.info("Connect to wifi: %s", self.__config[SSID])
        self.__wlan = WLAN(STA_IF)  # 创建 station 接口
        if self.__wlan.isconnected():
            self.__wlan.disconnect()
        self.__wlan.active(True)  # Activate the interface
        self.__wlan.scan()  # Scan
        self.__led.off()
        self.__wlan.config(dhcp_hostname=self.__hostname)
        self.__wlan.connect(self.__config[SSID],
                            self.__config[PASSWORD])  # 连接到指定ESSID网络
        if TIMEOUT in self.__config:
            self.__timeout = self.__config[TIMEOUT]

    def __set_properties(self):
        if self.__wlan.isconnected():
            log.info('network information: %r', self.__wlan.ifconfig())
            (self.ip, _, self.gw, self.dns) = self.__wlan.ifconfig()
            self.is_ok = True
            self.__led.on()
        else:
            self.ip = None
            self.gw = None
            self.dns = None
            self.is_ok = False
            self.__wlan = None
            self.__led.off()
        return self.is_ok

    def check_connection(self):
        if hw.WIFI_CHECK_TYPE == 0:
            return True
        if not self.is_connected():
            return False
        if hw.WIFI_CHECK_TYPE == 1:
            return True
        dest = self.gw
        if hw.WIFI_CHECK_TYPE == 3:
            if WIFI_CHECK_HOST in self.__config != None:
                dest = self.__config[WIFI_CHECK_HOST]
            else:
                dest = hw.WIFI_CHECK_HOST
        return ping_check(dest)

    async def monitor(self):
        log.debug("Setup wifi monitor")
        while hw.WIFI:
            try:
                await sleep(hw.WIFI_CHECK_INTVAL)
                if not self.check_connection():
                    log.info("Wifi is not ready, reconnecting...")
                    await self.async_connect(True)
            except:  #NOSONAR # pylint: disable=W0702
                pass
Пример #26
0
def check_open_network(ssid, wlan: WLAN) -> bool:
    result = connect_to_ap(wlan, ssid) and ping(SERVICE_ADDRESS)
    if wlan.isconnected():
        wlan.disconnect()
    return result
Пример #27
0
class MicroWifi:

    # ============================================================================
    # ===( Constants )============================================================
    # ============================================================================

    _ETH_AP = 1
    _ETH_STA = 0
    _IP_NONE = '0.0.0.0'
    _DEFAULT_AUTH_TYPE = WLAN.WPA2
    _AP_MASK = '255.255.255.0'
    _DEFAULT_TIMEOUT_SEC = 10

    # ============================================================================
    # ===( Utils  )===============================================================
    # ============================================================================

    @staticmethod
    def _mac2Str(binMac):
        return hexlify(binMac, ':').decode().upper()

    # ----------------------------------------------------------------------------

    def _setAPInfos(self,
                    ssid=None,
                    key=None,
                    ip=None,
                    mask=None,
                    gateway=None,
                    dns=None):
        self._apInfos = {
            'ssid': ssid,
            'key': key,
            'ip': ip,
            'mask': mask,
            'gateway': gateway,
            'dns': dns
        }

    # ----------------------------------------------------------------------------

    def _setConnectionInfos(self,
                            bssid=None,
                            ssid=None,
                            key=None,
                            ip=None,
                            mask=None,
                            gateway=None,
                            dns=None):
        self._connInfos = {
            'macBssid': bssid,
            'ssid': ssid,
            'key': key,
            'ip': ip,
            'mask': mask,
            'gateway': gateway,
            'dns': dns
        }

    # ----------------------------------------------------------------------------

    def _openConf(self):
        try:
            with open(self._filePath, 'r') as jsonFile:
                self._confObj = load(jsonFile)
        except:
            self._confObj = {}
        if self._confObj.get('STA', None) is None:
            self._confObj['STA'] = {}

    # ----------------------------------------------------------------------------

    def _writeConf(self):
        try:
            jsonStr = dumps(self._confObj)
            try:
                mkdir(self._confPath)
            except:
                pass
            jsonFile = open(self._filePath, 'wb')
            jsonFile.write(jsonStr)
            jsonFile.close()
            return True
        except:
            return False

    # ============================================================================
    # ===( Constructor )==========================================================
    # ============================================================================

    def __init__(self,
                 confName="wifi",
                 confPath="/flash/conf",
                 useExtAntenna=False):
        self._confPath = confPath
        self._filePath = '%s/%s.json' % (confPath, confName)
        self._wlan = WLAN()
        self._antenna = WLAN.EXT_ANT if useExtAntenna else WLAN.INT_ANT
        self._openConf()
        self._setAPInfos()
        self._setConnectionInfos()
        self._wlan.init(antenna=self._antenna)
        self.DisableRadio()

    # ============================================================================
    # ===( Functions )============================================================
    # ============================================================================

    def DisableRadio(self):
        self.CloseAccessPoint()
        self.CloseConnectionToAP()
        self._wlan.deinit()

    # ----------------------------------------------------------------------------

    def GetMACAddr(self):
        return self._mac2Str(self._wlan.mac())

    # ----------------------------------------------------------------------------

    def GetAPInfos(self):
        if not self.IsAccessPointOpened():
            self._setAPInfos()
        return self._apInfos

    # ----------------------------------------------------------------------------

    def GetConnectionInfos(self):
        if not self.IsConnectedToAP():
            self._setConnectionInfos()
        return self._connInfos

    # ----------------------------------------------------------------------------

    def ScanAP(self):
        try:
            if self._wlan.mode() == WLAN.STA:
                self._wlan.init(antenna=self._antenna)
            return self._wlan.scan()
        except:
            return ()

    # ----------------------------------------------------------------------------

    def OpenAccessPoint(self,
                        ssid,
                        key=None,
                        ip='192.168.0.254',
                        autoSave=True):
        if ssid and ip:
            try:
                self._wlan.ifconfig(id=self._ETH_AP,
                                    config=(ip, self._AP_MASK, ip, ip))
                auth = (self._DEFAULT_AUTH_TYPE, key) if key else None
                self._wlan.init(mode=WLAN.STA_AP,
                                ssid=ssid,
                                auth=auth,
                                antenna=self._antenna)
                print("WIFI ACCESS POINT OPENED :")
                print("  - MAC address  : %s" % self.GetMACAddr())
                print("  - Network SSID : %s" % ssid)
                print("  - IP address   : %s" % ip)
                print("  - Mask         : %s" % self._AP_MASK)
                print("  - Gateway IP   : %s" % ip)
                print("  - DNS server   : %s" % ip)
                if autoSave:
                    self._confObj['AP'] = {'ssid': ssid, 'key': key, 'ip': ip}
                    self._writeConf()
                self._setAPInfos(ssid, key, ip, self._AP_MASK, ip, ip)
                return True
            except:
                self.CloseAccessPoint()
        return False

    # ----------------------------------------------------------------------------

    def OpenAccessPointFromConf(self):
        try:
            ssid = self._confObj['AP']['ssid']
            key = self._confObj['AP']['key']
            ip = self._confObj['AP']['ip']
            return self.OpenAccessPoint(ssid, key, ip, False)
        except:
            return False

    # ----------------------------------------------------------------------------

    def RemoveAccessPointFromConf(self):
        try:
            del self._confObj['AP']
            return self._writeConf()
        except:
            return False

    # ----------------------------------------------------------------------------

    def CloseAccessPoint(self):
        try:
            ip = self._IP_NONE
            self._wlan.mode(WLAN.STA)
            self._wlan.ifconfig(id=self._ETH_AP, config=(ip, ip, ip, ip))
            return True
        except:
            return False

    # ----------------------------------------------------------------------------

    def IsAccessPointOpened(self):
        return self._wlan.ifconfig(self._ETH_AP)[0] != self._IP_NONE

    # ----------------------------------------------------------------------------

    def ConnectToAP(self,
                    ssid,
                    key=None,
                    macBssid=None,
                    timeoutSec=None,
                    autoSave=True):
        if ssid:
            if not key:
                key = ''
            if not timeoutSec:
                timeoutSec = self._DEFAULT_TIMEOUT_SEC
            timeout = timeoutSec * 1000
            if self._wlan.mode() == WLAN.STA:
                self._wlan.init(antenna=self._antenna)
            print("TRYING TO CONNECT WIFI TO AP %s..." % ssid)
            for ap in self.ScanAP():
                if ap.ssid == ssid and \
                   ( not macBssid or self._mac2Str(ap.bssid) == macBssid ) :
                    self._wlan.connect(ssid=ap.ssid,
                                       bssid=ap.bssid,
                                       auth=(self._DEFAULT_AUTH_TYPE, key),
                                       timeout=timeout)
                    t = ticks_ms()
                    while ticks_diff(t, ticks_ms()) < timeout:
                        sleep(0.100)
                        if self.IsConnectedToAP():
                            bssid = self._mac2Str(ap.bssid)
                            staCfg = self._wlan.ifconfig(id=self._ETH_STA)
                            ip = staCfg[0]
                            mask = staCfg[1]
                            gateway = staCfg[2]
                            dns = staCfg[3]
                            print("WIFI CONNECTED TO AP :")
                            print("  - MAC address   : %s" % self.GetMACAddr())
                            print("  - Network BSSID : %s" % bssid)
                            print("  - Network SSID  : %s" % ssid)
                            print("  - IP address    : %s" % ip)
                            print("  - Mask          : %s" % mask)
                            print("  - Gateway IP    : %s" % gateway)
                            print("  - DNS server    : %s" % dns)
                            if autoSave:
                                sta = {
                                    'ssid': ssid,
                                    'key': key,
                                }
                                self._confObj['STA'][bssid] = sta
                                self._writeConf()
                            self._setConnectionInfos(bssid, ssid, key, ip,
                                                     mask, gateway, dns)
                            return True
                    self.CloseConnectionToAP()
                    break
            print("FAILED TO CONNECT WIFI TO AP %s" % ssid)
        return False

    # ----------------------------------------------------------------------------

    def ConnectToAPFromConf(self, bssidMustBeSame=False, timeoutSec=None):
        if self._wlan.mode() == WLAN.STA:
            self._wlan.init(antenna=self._antenna)
        for ap in self.ScanAP():
            for bssid in self._confObj['STA']:
                macBssid = self._mac2Str(ap.bssid) if bssidMustBeSame else None
                if self._confObj['STA'][bssid]['ssid'] == ap.ssid and \
                   ( not macBssid or bssid == macBssid ) :
                    if self.ConnectToAP(ap.ssid,
                                        self._confObj['STA'][bssid]['key'],
                                        macBssid, timeoutSec, False):
                        return True
                    break
        return False

    # ----------------------------------------------------------------------------

    def RemoveConnectionToAPFromConf(self, ssid, macBssid=None):
        try:
            changed = False
            for bssid in list(self._confObj['STA']):
                if self._confObj['STA'][bssid]['ssid'] == ssid and \
                   ( not macBssid or bssid == macBssid ) :
                    del self._confObj['STA'][bssid]
                    changed = True
            if changed:
                return self._writeConf()
        except:
            pass
        return False

    # ----------------------------------------------------------------------------

    def CloseConnectionToAP(self):
        try:
            self._wlan.disconnect()
            self._wlan.ifconfig(id=self._ETH_STA, config='dhcp')
            return True
        except:
            return False

    # ----------------------------------------------------------------------------

    def IsConnectedToAP(self):
        return self._wlan.ifconfig(self._ETH_STA)[0] != self._IP_NONE

    # ----------------------------------------------------------------------------

    def ResolveIPFromHostname(self, hostname):
        originalMode = self._wlan.mode()
        if originalMode == WLAN.STA_AP:
            self._wlan.mode(WLAN.STA)
        try:
            ipResolved = getaddrinfo(hostname, 0)[0][-1][0]
        except:
            ipResolved = None
        if originalMode == WLAN.STA_AP:
            self._wlan.mode(WLAN.STA_AP)
        return ipResolved if ipResolved != self._IP_NONE else None

    # ----------------------------------------------------------------------------

    def InternetAccessIsPresent(self):
        return (self.ResolveIPFromHostname('iana.org') is not None)

    # ----------------------------------------------------------------------------

    def WaitForInternetAccess(self, timeoutSec=None):
        if not timeoutSec:
            timeoutSec = self._DEFAULT_TIMEOUT_SEC
        timeout = timeoutSec * 1000
        t = ticks_ms()
        while ticks_diff(t, ticks_ms()) < timeout:
            sleep(0.100)
            if self.InternetAccessIsPresent():
                return True
        return False
Пример #28
0
 def disconnectWLAN(self):
     # disconnedt wlan because it spams debug messages that disturb the monitor protocol
     from network import WLAN
     wlan = WLAN(mode=WLAN.STA)
     wlan.disconnect()
Пример #29
0
class WifiManager:
    def __init__(self, known_nets):
        self._known_nets = known_nets
        # create network in STAtion mode
        # pycom: device always starts up in AP-mode
        #self._wl = WLAN()
        #self._wl.mode(WLAN.STA)

    '''def print_debug(self, message):
        """print_debug() - for debugging """
        if USE_DEBUG:
            print(msg)
    '''

    # 2019-1203 new, due to Exception error in legacy WifiManager
    # pre-condition: self._known_nets is not None
    # post-condition: self._wl is created
    # returns: IP
    # URL: https://docs.pycom.io/tutorials/all/wlan/
    def connect(self):
        """connect() - connects device according to network parameters in JSON-file."""
        if machine.reset_cause() != machine.SOFT_RESET:
            # from network import WLAN
            self._wl = WLAN()
            self._wl.mode(WLAN.STA)
            original_ssid = self._wl.ssid()
            original_auth = self._wl.auth()

            print_debug("Wifimanager - scanning for known wifi nets...")
            available_nets = self._wl.scan()
            nets = frozenset([e.ssid for e in available_nets])

            known_nets_names = frozenset([key for key in self._known_nets])
            net_to_use = list(nets & known_nets_names)
            print_debug("Wifimanager - SSID to use...{}".format(net_to_use))
            try:
                net_to_use = net_to_use[0]
                print_debug("Wifimanager - net to use...{}".format(net_to_use))
                net_properties = self._known_nets[net_to_use]
                pwd = net_properties['pwd']
                sec = [e.sec for e in available_nets
                       if e.ssid == net_to_use][0]
                print_debug(
                    "Wifimanager - net_properties...{}".format(net_properties))
                if 'wlan_config' in net_properties:
                    print_debug("Wifimanager - wlan_config...{}".format(
                        net_properties['wlan_config']))
                    self._wl.ifconfig(config=net_properties['wlan_config'])
                self._wl.connect(net_to_use, (sec, pwd), timeout=10000)
                ip = self.wait_for_networking(1)
                self._ssid = net_to_use
                print_debug("Connected to " + net_to_use +
                            " with IP address:" + ip)

            except Exception as e:
                print(
                    "Failed to connect to any known network, going into AP mode"
                )
                self._wl.init(mode=WLAN.AP,
                              ssid=original_ssid,
                              auth=original_auth,
                              channel=6,
                              antenna=WLAN.INT_ANT)
                self._ssid = None

        else:
            print_debug("Already connected to " + net_to_use +
                        " with IP address:" + self._wl.ifconfig()[0])

        return self._wl.ifconfig()[0]

    def wait_for_networking(self, dt=1):
        """ wait unitil network is connected and returns IP"""
        station = self._wl  # network.WLAN(mode=network.WLAN.STA)
        while not station.isconnected():
            time.sleep(dt)
            machine.idle()
        ip = station.ifconfig()[0]
        return ip

    # wrapper for disconnecting network
    def disconnect(self):
        """disconnect() - de-activate network interface, but leaves Wifi radio on"""
        self._wl.disconnect(
        )  # pycom - disconnect from Wifi, but leave Wif radio on.
        print_debug('WifiManager::Wifi disconnected')

    # wrapper for disabling Wifi radio
    def deinit(self):
        """deinit() - disable Wifi radio"""
        self._wl.deint()  # pycom
        print_debug('WifiManager::Wifi radio off')

    # wrapper for network scan
    def scan(self):
        """scan() - Performs a network scan and returns a list
        of named tuples with (ssid, bssid, sec, channel, rssi)
        """
        return self._wl.scan()

    def change_access(self, user=None, passwrd=None):
        """change_access - change password for telnet and ftp access"""
        if (user is None) or (passwrd is None):
            print('WifiManager:: username and password must be specified')
            return

        server = Server()  # from network
        # disable the server
        server.deinit()
        # enable the server again with new credentials
        # for ftp and telnet, not USB
        server.init(login=(user, passwrd), timeout=600)
        print_debug('WifiManager::password {} is changed...'.format(user))

    # wrappers for wlan settings.
    @property
    def ssid(self):
        """ ssid() - returns SSID of connected Wifi network"""
        return self._ssid

    @property
    def isconnected(self):
        """isconnected() - returns if connected to Wifi (True)
        or not (False)"""
        return self._wl.isconnected()

    @property
    def ip(self):
        """ip() - returns IP of device on connected Wifi network"""
        return self._wl.ifconfig()[0]

    @property
    def mac(self):
        """returns MAC-address of device"""
        mac = hexlify(self._wl.mac(), ':').decode()  # pycom
        # return (mac) # lower case
        return mac.upper()

    # ================================================
    # legacy methods
    # ================================================
    import json

    def __readjson(self, jsonfile):
        """readjson(file) - returns the contents of file in JSON-format"""
        with open(jsonfile, 'r') as infile:
            config = json.load(infile)
        if USE_DEBUG:
            print('WifiManager::JSON settings: {}'.format(config))
        return config
Пример #30
0
wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=10000)
wait_for_connection(wifi)

wifi.ifconfig(config='dhcp')
wait_for_connection(wifi)
print('0.0.0.0' not in wifi.ifconfig())
wifi.ifconfig(0,
              ('192.168.178.109', '255.255.255.0', '192.168.178.1', '8.8.8.8'))
wait_for_connection(wifi)
print(
    wifi.ifconfig(0) == ('192.168.178.109', '255.255.255.0', '192.168.178.1',
                         '8.8.8.8'))
wait_for_connection(wifi)

print(wifi.isconnected() == True)
wifi.disconnect()
print(wifi.isconnected() == False)

t0 = time.ticks_ms()
wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=0)
print(time.ticks_ms() - t0 < 500)

wifi.disconnect()
print(wifi.isconnected() == False)

# test init again
wifi.init(WLAN.AP,
          ssid='www.wipy.io',
          auth=None,
          channel=5,
          antenna=WLAN.INT_ANT)
Пример #31
0
            print("------ Sending an ACK")
            lora_sock.send(ack_pkg)

            #msg="{\"value\":"+str(some_number)+"}")
            pycom.rgbled(colorgreen)  # green
            time.sleep(1)
            # Do any extra processing required for the package. Keep in mind it should be as fast as posible
            # to make sure that the other clients are not waiting too long for their messages to be ac
except ValueError:
    print(ValueError)
    pycom.rgbled(0x0F0000)
    print(
        "--------------------- An exception occurred(1) ! ---------------------"
    )
    machine.reset()

except Exception as e:
    pycom.rgbled(0x0F0000)
    print(e)
    print(
        "--------------------- An exception occurred(2) ! ---------------------"
    )
#  machine.reset()
finally:  # If an exception is thrown ...
    client.disconnect()  # ... disconnect the client and clean up.
    client = None
    wlan.disconnect()
    wlan = None
    pycom.rgbled(0x000022)  # Status blue: stopped
    print("Disconnected from Bluemix")
Пример #32
0
class WifiManager:
    def __init__(self, jsonfile):
        # Load Wifi configuration from JSON file.
        self._config = self.readjson(jsonfile)
        # create network in STAtion mode
        self._wlan = WLAN(STA_IF)

    def connect(self):
        """connect() - connects device according to network parameters
           in config-file."""
        # check if network is connected. If yes: return, finished
        # 2019-0801 changed: if self._wlan.isconnected():
        if self.isconnected:
            if USE_DEBUG:
                print('WLAN already connected')
            return self._wlan.ifconfig()

        # activate Wifi interface
        if self._wlan.active() is False:
            self._wlan.active(True)
        # scan available networks for the required one
        nets = self._wlan.scan()
        for net in nets:
            ssid = net[0]
            if ssid == bytearray(self._config['SSID']):  # must use bytearray!
                if USE_DEBUG:
                    print("Startup WiFi ..." + self._config['SSID'])
                # specify if static or dynamic IP is requested
                # STATIC IP: an IP is given
                # DYNAMIC IP: None
                if self._config['STATIC_IP'] is not '':
                    if USE_DEBUG:
                        print('WifiManager::Static IP configuration')
                    # configure network for static IP
                    self._wlan.ifconfig(
                        (self._config['STATIC_IP'], self._config['MASKER'],
                         self._config['GATEWAY_IP'], self._config['DNS']))

                # connect to SSID... either for STATIC or DYNAMIC IP
                self._wlan.connect(self._config['SSID'],
                                   self._config['PASSWRD'])
                while not self.isconnected:
                    idle()  # save power while waiting
                    time.sleep_ms(100)  # give it some time
                if USE_DEBUG:
                    print("Network '{}' connection succeeded!".format(ssid))
                break

        # check connection, if not succesfull: raise exception
        if not self._wlan.active():
            raise exception('Network {0} not found.'.format(ssid))

        # returns network configuration...
        # although 'myPy.local' should work on MacOS X (Bonjour)
        return self._wlan.ifconfig()

    def readjson(self, jsonfile):
        """readjson(file) - returns the contents of a JSON file"""
        with open(jsonfile, 'r') as infile:
            config = json.load(infile)
        return config

    def print_config(self):
        """print_config() - print config data on screen."""
        for key in self._config.keys():
            print('[{0}] = {1}'.format(key, self._config[key]))

    # wrapper for network scan
    def scan(self):
        """scan() - Performs a network scan and returns a list
        of named tuples with (ssid, bssid, sec, channel, rssi)
        """
        if self.isconnected is False:
            return False
        nets = self._wlan.scan()
        nets_list = {}
        for net in nets:
            nets_list['SSID'] = str(net[0], 'utf8')
            # nets_list['bssid'] = str(net[1])
            nets_list['CHANNEL'] = str(net[2])
            nets_list['RSSI'] = str(net[3]) + ' dBm'
            nets_list['SECURITY'] = self._get_secure(net[4])
            print(nets_list)

    def _get_secure(self, num):
        security = [
            'Open Wifi',  # 0
            'WEP',  # 1
            'WPA-PSK',  # 2
            'WPA2-PSK',  # 3
            'WPA/WP2-PSK'  # 4
        ]
        if num < len(security):
            return security[num]
        else:
            return str(num)

    def disconnect(self):
        """disconnect() - disconnect the Wifi connection"""
        self._wlan.disconnect()
        time.sleep_ms(50)  # give it time, trial-and-error value
        return self.isconnected

    @property
    def isconnected(self):
        """isconnected() - returns True when device is connected to wifi,
        else False """
        return self._wlan.isconnected()

    @property
    def mac(self):
        """returns MAC-address of device"""
        mac = hexlify(WLAN().config('mac'), ':').decode()
        return mac.upper()  # MAC-address in upper case
class NanoGateway:
    """
    Nano gateway class, set up by default for use with TTN, but can be configured
    for any other network supporting the Semtech Packet Forwarder.
    Only required configuration is wifi_ssid and wifi_password which are used for
    connecting to the Internet.
    """
    def __init__(self,
                 id,
                 frequency,
                 datarate,
                 ssid,
                 password,
                 server,
                 port,
                 ntp_server='pool.ntp.org',
                 ntp_period=3600):
        self.id = id
        self.server = server
        self.port = port

        self.frequency = frequency
        self.datarate = datarate

        self.ssid = ssid
        self.password = password

        self.ntp_server = ntp_server
        self.ntp_period = ntp_period

        self.server_ip = None

        self.rxnb = 0
        self.rxok = 0
        self.rxfw = 0
        self.dwnb = 0
        self.txnb = 0

        self.sf = self._dr_to_sf(self.datarate)
        self.bw = self._dr_to_bw(self.datarate)

        self.stat_alarm = None
        self.pull_alarm = None
        self.uplink_alarm = None

        self.wlan = None
        self.sock = None
        self.udp_stop = False
        self.udp_lock = _thread.allocate_lock()

        self.lora = None
        self.lora_sock = None

        self.rtc = machine.RTC()

    def start(self):
        """
        Starts the LoRaWAN nano gateway.
        """

        self._log('Starting LoRaWAN nano gateway with id: {}', self.id)

        # setup WiFi as a station and connect
        self.wlan = WLAN(mode=WLAN.STA)
        self._connect_to_wifi()

        # get a time sync
        self._log('Syncing time with {} ...', self.ntp_server)
        self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
        while not self.rtc.synced():
            utime.sleep_ms(50)
        self._log("RTC NTP sync complete")

        # get the server IP and create an UDP socket
        self.server_ip = usocket.getaddrinfo(self.server, self.port)[0][-1]
        self._log('Opening UDP socket to {} ({}) port {}...', self.server,
                  self.server_ip[0], self.server_ip[1])
        self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM,
                                   usocket.IPPROTO_UDP)
        self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
        self.sock.setblocking(False)

        # push the first time immediatelly
        self._push_data(self._make_stat_packet())

        # create the alarms
        self.stat_alarm = Timer.Alarm(
            handler=lambda t: self._push_data(self._make_stat_packet()),
            s=60,
            periodic=True)
        self.pull_alarm = Timer.Alarm(handler=lambda u: self._pull_data(),
                                      s=25,
                                      periodic=True)

        # start the UDP receive thread
        self.udp_stop = False
        _thread.start_new_thread(self._udp_thread, ())

        # initialize the LoRa radio in LORA mode
        self._log('Setting up the LoRa radio at {} Mhz using {}',
                  self._freq_to_float(self.frequency), self.datarate)
        self.lora = LoRa(mode=LoRa.LORA,
                         frequency=self.frequency,
                         bandwidth=self.bw,
                         sf=self.sf,
                         preamble=8,
                         coding_rate=LoRa.CODING_4_5,
                         tx_iq=True)

        # create a raw LoRa socket
        self.lora_sock = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW)
        self.lora_sock.setblocking(False)
        self.lora_tx_done = False

        self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT
                                    | LoRa.TX_PACKET_EVENT),
                           handler=self._lora_cb)
        self._log('LoRaWAN nano gateway online')

    def stop(self):
        """
        Stops the LoRaWAN nano gateway.
        """

        self._log('Stopping...')

        # send the LoRa radio to sleep
        self.lora.callback(trigger=None, handler=None)
        self.lora.power_mode(LoRa.SLEEP)

        # stop the NTP sync
        self.rtc.ntp_sync(None)

        # cancel all the alarms
        self.stat_alarm.cancel()
        self.pull_alarm.cancel()

        # signal the UDP thread to stop
        self.udp_stop = True
        while self.udp_stop:
            utime.sleep_ms(50)

        # disable WLAN
        self.wlan.disconnect()
        self.wlan.deinit()

    def _connect_to_wifi(self):
        self.wlan.connect(self.ssid, auth=(None, self.password))
        while not self.wlan.isconnected():
            utime.sleep_ms(50)
        self._log('WiFi connected to: {}', self.ssid)

    def _dr_to_sf(self, dr):
        sf = dr[2:4]
        if sf[1] not in '0123456789':
            sf = sf[:1]
        return int(sf)

    def _dr_to_bw(self, dr):
        bw = dr[-5:]
        if bw == 'BW125':
            return LoRa.BW_125KHZ
        elif bw == 'BW250':
            return LoRa.BW_250KHZ
        else:
            return LoRa.BW_500KHZ

    def _sf_bw_to_dr(self, sf, bw):
        dr = 'SF' + str(sf)
        if bw == LoRa.BW_125KHZ:
            return dr + 'BW125'
        elif bw == LoRa.BW_250KHZ:
            return dr + 'BW250'
        else:
            return dr + 'BW500'

    def _lora_cb(self, lora):
        """
        LoRa radio events callback handler.
        """

        events = lora.events()
        if events & LoRa.RX_PACKET_EVENT:
            self.rxnb += 1
            self.rxok += 1
            rx_data = self.lora_sock.recv(256)
            stats = lora.stats()
            packet = self._make_node_packet(rx_data, self.rtc.now(),
                                            stats.rx_timestamp, stats.sfrx,
                                            self.bw, stats.rssi, stats.snr)
            self._push_data(packet)
            self._log('Received packet: {}', packet)
            self.rxfw += 1
        if events & LoRa.TX_PACKET_EVENT:
            self.txnb += 1
            lora.init(mode=LoRa.LORA,
                      frequency=self.frequency,
                      bandwidth=self.bw,
                      sf=self.sf,
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True)

    def _freq_to_float(self, frequency):
        """
        MicroPython has some inprecision when doing large float division.
        To counter this, this method first does integer division until we
        reach the decimal breaking point. This doesn't completely elimate
        the issue in all cases, but it does help for a number of commonly
        used frequencies.
        """

        divider = 6
        while divider > 0 and frequency % 10 == 0:
            frequency = frequency // 10
            divider -= 1
        if divider > 0:
            frequency = frequency / (10**divider)
        return frequency

    def _make_stat_packet(self):
        now = self.rtc.now()
        STAT_PK["stat"]["time"] = "%d-%02d-%02d %02d:%02d:%02d GMT" % (
            now[0], now[1], now[2], now[3], now[4], now[5])
        STAT_PK["stat"]["rxnb"] = self.rxnb
        STAT_PK["stat"]["rxok"] = self.rxok
        STAT_PK["stat"]["rxfw"] = self.rxfw
        STAT_PK["stat"]["dwnb"] = self.dwnb
        STAT_PK["stat"]["txnb"] = self.txnb
        return ujson.dumps(STAT_PK)

    def _make_node_packet(self, rx_data, rx_time, tmst, sf, bw, rssi, snr):
        RX_PK["rxpk"][0]["time"] = "%d-%02d-%02dT%02d:%02d:%02d.%dZ" % (
            rx_time[0], rx_time[1], rx_time[2], rx_time[3], rx_time[4],
            rx_time[5], rx_time[6])
        RX_PK["rxpk"][0]["tmst"] = tmst
        RX_PK["rxpk"][0]["freq"] = self._freq_to_float(self.frequency)
        RX_PK["rxpk"][0]["datr"] = self._sf_bw_to_dr(sf, bw)
        RX_PK["rxpk"][0]["rssi"] = rssi
        RX_PK["rxpk"][0]["lsnr"] = snr
        RX_PK["rxpk"][0]["data"] = ubinascii.b2a_base64(rx_data)[:-1]
        RX_PK["rxpk"][0]["size"] = len(rx_data)
        return ujson.dumps(RX_PK)

    def _push_data(self, data):
        token = uos.urandom(2)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes(
            [PUSH_DATA]) + ubinascii.unhexlify(self.id) + data
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('Failed to push uplink packet to server: {}', ex)

    def _pull_data(self):
        token = uos.urandom(2)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes(
            [PULL_DATA]) + ubinascii.unhexlify(self.id)
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('Failed to pull downlink packets from server: {}',
                          ex)

    def _ack_pull_rsp(self, token, error):
        TX_ACK_PK["txpk_ack"]["error"] = error
        resp = ujson.dumps(TX_ACK_PK)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes(
            [PULL_ACK]) + ubinascii.unhexlify(self.id) + resp
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('PULL RSP ACK exception: {}', ex)

    def _send_down_link(self, data, tmst, datarate, frequency):
        """
        Transmits a downlink message over LoRa.
        """

        self.lora.init(mode=LoRa.LORA,
                       frequency=frequency,
                       bandwidth=self._dr_to_bw(datarate),
                       sf=self._dr_to_sf(datarate),
                       preamble=8,
                       coding_rate=LoRa.CODING_4_5,
                       tx_iq=True)
        while utime.ticks_cpu() < tmst:
            pass
        self.lora_sock.send(data)
        self._log(
            'Sent downlink packet scheduled on {:.3f}, at {:.3f} Mhz using {}: {}',
            tmst / 1000000, self._freq_to_float(frequency), datarate, data)

    def _udp_thread(self):
        """
        UDP thread, reads data from the server and handles it.
        """

        while not self.udp_stop:
            try:
                data, src = self.sock.recvfrom(1024)
                _token = data[1:3]
                _type = data[3]
                if _type == PUSH_ACK:
                    self._log("Push ack")
                elif _type == PULL_ACK:
                    self._log("Pull ack")
                elif _type == PULL_RESP:
                    self.dwnb += 1
                    ack_error = TX_ERR_NONE
                    tx_pk = ujson.loads(data[4:])
                    tmst = tx_pk["txpk"]["tmst"]
                    t_us = tmst - utime.ticks_cpu() - 15000
                    if t_us < 0:
                        t_us += 0xFFFFFFFF
                    if t_us < 20000000:
                        self.uplink_alarm = Timer.Alarm(
                            handler=lambda x: self._send_down_link(
                                ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                tx_pk["txpk"]["tmst"] - 50, tx_pk["txpk"][
                                    "datr"],
                                int(tx_pk["txpk"]["freq"] * 1000) * 1000),
                            us=t_us)
                    else:
                        ack_error = TX_ERR_TOO_LATE
                        self._log('Downlink timestamp error!, t_us: {}', t_us)
                    self._ack_pull_rsp(_token, ack_error)
                    self._log("Pull rsp")
            except usocket.timeout:
                pass
            except OSError as ex:
                if ex.errno != errno.EAGAIN:
                    self._log('UDP recv OSError Exception: {}', ex)
            except Exception as ex:
                self._log('UDP recv Exception: {}', ex)

            # wait before trying to receive again
            utime.sleep_ms(UDP_THREAD_CYCLE_MS)

        # we are to close the socket
        self.sock.close()
        self.udp_stop = False
        self._log('UDP thread stopped')

    def _log(self, message, *args):
        """
        Outputs a log message to stdout.
        """

        print('[{:>10.3f}] {}'.format(utime.ticks_ms() / 1000,
                                      str(message).format(*args)))
Пример #34
0
class NanoGateway:
    """
    Nano gateway class, set up by default for use with TTN, but can be configured
    for any other network supporting the Semtech Packet Forwarder.
    Only required configuration is wifi_ssid and wifi_password which are used for
    connecting to the Internet.
    """

    def __init__(self, id, frequency, datarate, ssid, password, server, port, ntp_server='pool.ntp.org', ntp_period=3600):
        self.id = id
        self.server = server
        self.port = port

        self.frequency = frequency
        self.datarate = datarate

        self.ssid = ssid
        self.password = password

        self.ntp_server = ntp_server
        self.ntp_period = ntp_period

        self.server_ip = None

        self.rxnb = 0
        self.rxok = 0
        self.rxfw = 0
        self.dwnb = 0
        self.txnb = 0

        self.sf = self._dr_to_sf(self.datarate)
        self.bw = self._dr_to_bw(self.datarate)

        self.stat_alarm = None
        self.pull_alarm = None
        self.uplink_alarm = None

        self.wlan = None
        self.sock = None
        self.udp_stop = False
        self.udp_lock = _thread.allocate_lock()

        self.lora = None
        self.lora_sock = None

        self.rtc = machine.RTC()

    def start(self):
        """
        Starts the LoRaWAN nano gateway.
        """

        self._log('Starting LoRaWAN nano gateway with id: {}', self.id)

        # setup WiFi as a station and connect
        self.wlan = WLAN(mode=WLAN.STA)
        self._connect_to_wifi()

        # get a time sync
        self._log('Syncing time with {} ...', self.ntp_server)
        self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
        while not self.rtc.synced():
            utime.sleep_ms(50)
        self._log("RTC NTP sync complete")

        # get the server IP and create an UDP socket
        self.server_ip = usocket.getaddrinfo(self.server, self.port)[0][-1]
        self._log('Opening UDP socket to {} ({}) port {}...', self.server, self.server_ip[0], self.server_ip[1])
        self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM, usocket.IPPROTO_UDP)
        self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
        self.sock.setblocking(False)

        # push the first time immediatelly
        self._push_data(self._make_stat_packet())

        # create the alarms
        self.stat_alarm = Timer.Alarm(handler=lambda t: self._push_data(self._make_stat_packet()), s=60, periodic=True)
        self.pull_alarm = Timer.Alarm(handler=lambda u: self._pull_data(), s=25, periodic=True)

        # start the UDP receive thread
        self.udp_stop = False
        _thread.start_new_thread(self._udp_thread, ())

        # initialize the LoRa radio in LORA mode
        self._log('Setting up the LoRa radio at {:.1f} Mhz using {}', self._freq_to_float(self.frequency), self.datarate)
        self.lora = LoRa(
            mode=LoRa.LORA,
            frequency=self.frequency,
            bandwidth=self.bw,
            sf=self.sf,
            preamble=8,
            coding_rate=LoRa.CODING_4_5,
            tx_iq=True
        )

        # create a raw LoRa socket
        self.lora_sock = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW)
        self.lora_sock.setblocking(False)
        self.lora_tx_done = False

        self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT), handler=self._lora_cb)
        self._log('LoRaWAN nano gateway online')

    def stop(self):
        """
        Stops the LoRaWAN nano gateway.
        """

        self._log('Stopping...')

        # send the LoRa radio to sleep
        self.lora.callback(trigger=None, handler=None)
        self.lora.power_mode(LoRa.SLEEP)

        # stop the NTP sync
        self.rtc.ntp_sync(None)

        # cancel all the alarms
        self.stat_alarm.cancel()
        self.pull_alarm.cancel()

        # signal the UDP thread to stop
        self.udp_stop = True
        while self.udp_stop:
            utime.sleep_ms(50)

        # disable WLAN
        self.wlan.disconnect()
        self.wlan.deinit()

    def _connect_to_wifi(self):
        self.wlan.connect(self.ssid, auth=(None, self.password))
        while not self.wlan.isconnected():
            utime.sleep_ms(50)
        self._log('WiFi connected to: {}', self.ssid)

    def _dr_to_sf(self, dr):
        sf = dr[2:4]
        if sf[1] not in '0123456789':
            sf = sf[:1]
        return int(sf)

    def _dr_to_bw(self, dr):
        bw = dr[-5:]
        if bw == 'BW125':
            return LoRa.BW_125KHZ
        elif bw == 'BW250':
            return LoRa.BW_250KHZ
        else:
            return LoRa.BW_500KHZ

    def _sf_bw_to_dr(self, sf, bw):
        dr = 'SF' + str(sf)
        if bw == LoRa.BW_125KHZ:
            return dr + 'BW125'
        elif bw == LoRa.BW_250KHZ:
            return dr + 'BW250'
        else:
            return dr + 'BW500'

    def _lora_cb(self, lora):
        """
        LoRa radio events callback handler.
        """

        events = lora.events()
        if events & LoRa.RX_PACKET_EVENT:
            self.rxnb += 1
            self.rxok += 1
            rx_data = self.lora_sock.recv(256)
            stats = lora.stats()
            packet = self._make_node_packet(rx_data, self.rtc.now(), stats.rx_timestamp, stats.sfrx, self.bw, stats.rssi, stats.snr)
            self._push_data(packet)
            self._log('Received packet: {}', packet)
            self.rxfw += 1
        if events & LoRa.TX_PACKET_EVENT:
            self.txnb += 1
            lora.init(
                mode=LoRa.LORA,
                frequency=self.frequency,
                bandwidth=self.bw,
                sf=self.sf,
                preamble=8,
                coding_rate=LoRa.CODING_4_5,
                tx_iq=True
                )

    def _freq_to_float(self, frequency):
        """
        MicroPython has some inprecision when doing large float division.
        To counter this, this method first does integer division until we
        reach the decimal breaking point. This doesn't completely elimate
        the issue in all cases, but it does help for a number of commonly
        used frequencies.
        """

        divider = 6
        while divider > 0 and frequency % 10 == 0:
            frequency = frequency // 10
            divider -= 1
        if divider > 0:
            frequency = frequency / (10 ** divider)
        return frequency

    def _make_stat_packet(self):
        now = self.rtc.now()
        STAT_PK["stat"]["time"] = "%d-%02d-%02d %02d:%02d:%02d GMT" % (now[0], now[1], now[2], now[3], now[4], now[5])
        STAT_PK["stat"]["rxnb"] = self.rxnb
        STAT_PK["stat"]["rxok"] = self.rxok
        STAT_PK["stat"]["rxfw"] = self.rxfw
        STAT_PK["stat"]["dwnb"] = self.dwnb
        STAT_PK["stat"]["txnb"] = self.txnb
        return ujson.dumps(STAT_PK)

    def _make_node_packet(self, rx_data, rx_time, tmst, sf, bw, rssi, snr):
        RX_PK["rxpk"][0]["time"] = "%d-%02d-%02dT%02d:%02d:%02d.%dZ" % (rx_time[0], rx_time[1], rx_time[2], rx_time[3], rx_time[4], rx_time[5], rx_time[6])
        RX_PK["rxpk"][0]["tmst"] = tmst
        RX_PK["rxpk"][0]["freq"] = self._freq_to_float(self.frequency)
        RX_PK["rxpk"][0]["datr"] = self._sf_bw_to_dr(sf, bw)
        RX_PK["rxpk"][0]["rssi"] = rssi
        RX_PK["rxpk"][0]["lsnr"] = snr
        RX_PK["rxpk"][0]["data"] = ubinascii.b2a_base64(rx_data)[:-1]
        RX_PK["rxpk"][0]["size"] = len(rx_data)
        return ujson.dumps(RX_PK)

    def _push_data(self, data):
        token = uos.urandom(2)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes([PUSH_DATA]) + ubinascii.unhexlify(self.id) + data
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('Failed to push uplink packet to server: {}', ex)

    def _pull_data(self):
        token = uos.urandom(2)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_DATA]) + ubinascii.unhexlify(self.id)
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('Failed to pull downlink packets from server: {}', ex)

    def _ack_pull_rsp(self, token, error):
        TX_ACK_PK["txpk_ack"]["error"] = error
        resp = ujson.dumps(TX_ACK_PK)
        packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_ACK]) + ubinascii.unhexlify(self.id) + resp
        with self.udp_lock:
            try:
                self.sock.sendto(packet, self.server_ip)
            except Exception as ex:
                self._log('PULL RSP ACK exception: {}', ex)

    def _send_down_link(self, data, tmst, datarate, frequency):
        """
        Transmits a downlink message over LoRa.
        """

        self.lora.init(
            mode=LoRa.LORA,
            frequency=frequency,
            bandwidth=self._dr_to_bw(datarate),
            sf=self._dr_to_sf(datarate),
            preamble=8,
            coding_rate=LoRa.CODING_4_5,
            tx_iq=True
            )
        while utime.ticks_us() < tmst:
            pass
        self.lora_sock.send(data)
        self._log(
            'Sent downlink packet scheduled on {:.3f}, at {:.1f} Mhz using {}: {}',
            tmst / 1000000,
            self._freq_to_float(frequency),
            datarate,
            data
        )

    def _udp_thread(self):
        """
        UDP thread, reads data from the server and handles it.
        """

        while not self.udp_stop:
            try:
                data, src = self.sock.recvfrom(1024)
                _token = data[1:3]
                _type = data[3]
                if _type == PUSH_ACK:
                    self._log("Push ack")
                elif _type == PULL_ACK:
                    self._log("Pull ack")
                elif _type == PULL_RESP:
                    self.dwnb += 1
                    ack_error = TX_ERR_NONE
                    tx_pk = ujson.loads(data[4:])
                    tmst = tx_pk["txpk"]["tmst"]
                    t_us = tmst - utime.ticks_us() - 12500
                    if t_us < 0:
                        t_us += 0xFFFFFFFF
                    if t_us < 20000000:
                        self.uplink_alarm = Timer.Alarm(
                            handler=lambda x: self._send_down_link(
                                ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                tx_pk["txpk"]["tmst"] - 50, tx_pk["txpk"]["datr"],
                                int(tx_pk["txpk"]["freq"] * 1000000)
                            ), 
                            us=t_us
                        )
                    else:
                        ack_error = TX_ERR_TOO_LATE
                        self._log('Downlink timestamp error!, t_us: {}', t_us)
                    self._ack_pull_rsp(_token, ack_error)
                    self._log("Pull rsp")
            except usocket.timeout:
                pass
            except OSError as ex:
                if ex.errno != errno.EAGAIN:
                    self._log('UDP recv OSError Exception: {}', ex)
            except Exception as ex:
                self._log('UDP recv Exception: {}', ex)

            # wait before trying to receive again
            utime.sleep_ms(UDP_THREAD_CYCLE_MS)

        # we are to close the socket
        self.sock.close()
        self.udp_stop = False
        self._log('UDP thread stopped')

    def _log(self, message, *args):
        """
        Outputs a log message to stdout.
        """

        print('[{:>10.3f}] {}'.format(
            utime.ticks_ms() / 1000,
            str(message).format(*args)
            ))