Module meshtastic.supported_device

Supported Meshtastic Devices - This is a class and collection of Meshtastic devices. It is used for auto detection as to which device might be connected.

Expand source code
""" Supported Meshtastic Devices - This is a class and collection of Meshtastic devices.
    It is used for auto detection as to which device might be connected.
"""

import platform
import subprocess
import re

# Goal is to detect which device and port to use from the supported devices
# without installing any libraries that are not currently in the python meshtastic library

class SupportedDevice():
    """Devices supported on Meshtastic"""

    def __init__(self, name, version=None, for_firmware=None, device_class="esp32",
                 baseport_on_linux=None, baseport_on_mac=None, baseport_on_windows="COM",
                 usb_vendor_id_in_hex=None, usb_product_id_in_hex=None):
        """ constructor """
        self.name = name
        self.version = version
        self.for_firmware = for_firmware
        self.device_class = device_class # could be "nrf52"

        # when you run "lsusb -d xxxx:" in linux
        self.usb_vendor_id_in_hex = usb_vendor_id_in_hex # store in lower case
        self.usb_product_id_in_hex = usb_product_id_in_hex # store in lower case

        self.baseport_on_linux = baseport_on_linux # ex: ttyUSB or ttyACM
        self.baseport_on_mac = baseport_on_mac
        self.baseport_on_windows = baseport_on_windows

# supported devices
tbeam_v0_7 = SupportedDevice(name="T-Beam", version="0.7", for_firmware="tbeam0.7",
                             baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                             usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_v1_1 = SupportedDevice(name="T-Beam", version="1.1", for_firmware="tbeam",
                             baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                             usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_M8N = SupportedDevice(name="T-Beam", version="M8N", for_firmware="tbeam",
                            baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                            usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_M8N_SX1262 = SupportedDevice(name="T-Beam", version="M8N_SX1262", for_firmware="tbeam",
                                   baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                                   usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v1_1 = SupportedDevice(name="T-Lora", version="1.1", for_firmware="tlora-v1",
                             baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial",
                             usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
tlora_v1_3 = SupportedDevice(name="T-Lora", version="1.3", for_firmware="tlora-v1-3",
                             baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial",
                             usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
tlora_v2_0 = SupportedDevice(name="T-Lora", version="2.0", for_firmware="tlora-v2-1",
                             baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                             usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v2_1 = SupportedDevice(name="T-Lora", version="2.1", for_firmware="tlora-v2-1",
                             baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                             usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v2_1_1_6 = SupportedDevice(name="T-Lora", version="2.1-1.6", for_firmware="tlora-v2-1-1.6",
                             baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                             usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
heltec_v1 = SupportedDevice(name="Heltec", version="1", for_firmware="heltec-v1",
                            baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
                            usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
heltec_v2_0 = SupportedDevice(name="Heltec", version="2.0", for_firmware="heltec-v2.0",
                              baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
                              usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
heltec_v2_1 = SupportedDevice(name="Heltec", version="2.1", for_firmware="heltec-v2.1",
                              baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
                              usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
rak11200 = SupportedDevice(name="RAK 11200", version="", for_firmware="rak11200",
                              baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
                              usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="7523")
meshtastic_diy_v1 = SupportedDevice(name="Meshtastic DIY", version="1", for_firmware="meshtastic-diy-v1",
                              baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
                              usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
# Note: The T-Echo reports product id in boot mode
techo_1 = SupportedDevice(name="T-Echo", version="1", for_firmware="t-echo-1", device_class="nrf52",
                              baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                              usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029")
rak4631_5005 = SupportedDevice(name="RAK 4631 5005", version="", for_firmware="rak4631_5005",
                               device_class="nrf52",
                               baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                               usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029")
# Note: The 19003 reports same product id as 5005 in boot mode
rak4631_19003 = SupportedDevice(name="RAK 4631 19003", version="", for_firmware="rak4631_19003",
                                device_class="nrf52",
                                baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
                                usb_vendor_id_in_hex="239a", usb_product_id_in_hex="8029")

supported_devices = [tbeam_v0_7, tbeam_v1_1, tbeam_M8N, tbeam_M8N_SX1262,
                     tlora_v1_1, tlora_v1_3, tlora_v2_0, tlora_v2_1, tlora_v2_1_1_6,
                     heltec_v1, heltec_v2_0, heltec_v2_1,
                     meshtastic_diy_v1, techo_1, rak4631_5005, rak4631_19003,
                     rak11200]


def get_unique_vendor_ids():
    """Return a set of unique vendor ids"""
    vids = set()
    for d in supported_devices:
        if d.usb_vendor_id_in_hex:
            vids.add(d.usb_vendor_id_in_hex)
    return vids

def get_devices_with_vendor_id(vid):
    """Return a set of unique devices with the vendor id"""
    sd = set()
    for d in supported_devices:
        if d.usb_vendor_id_in_hex == vid:
            sd.add(d)
    return sd

def active_ports_on_supported_devices(sds):
    """Return a set of active ports based on the supplied supported devices"""
    ports = set()
    baseports = set()
    system = platform.system()

    # figure out what possible base ports there are
    for d in sds:
        if system == "Linux":
            baseports.add(d.baseport_on_linux)
        elif system == "Darwin":
            baseports.add(d.baseport_on_mac)
        elif system == "Windows":
            baseports.add(d.baseport_on_windows)

    for bp in baseports:
        if system == "Linux":
            # see if we have any devices (ignoring any stderr output)
            command = f'ls -al /dev/{bp}* 2> /dev/null'
            #print(f'command:{command}')
            _, ls_output = subprocess.getstatusoutput(command)
            #print(f'ls_output:{ls_output}')
            # if we got output, there are ports
            if len(ls_output) > 0:
                #print('got output')
                # for each line of output
                lines = ls_output.split('\n')
                #print(f'lines:{lines}')
                for line in lines:
                    parts = line.split(' ')
                    #print(f'parts:{parts}')
                    port = parts[-1]
                    #print(f'port:{port}')
                    ports.add(port)
        elif system == "Darwin":
            # see if we have any devices (ignoring any stderr output)
            command = f'ls -al /dev/{bp}* 2> /dev/null'
            #print(f'command:{command}')
            _, ls_output = subprocess.getstatusoutput(command)
            #print(f'ls_output:{ls_output}')
            # if we got output, there are ports
            if len(ls_output) > 0:
                #print('got output')
                # for each line of output
                lines = ls_output.split('\n')
                #print(f'lines:{lines}')
                for line in lines:
                    parts = line.split(' ')
                    #print(f'parts:{parts}')
                    port = parts[-1]
                    #print(f'port:{port}')
                    ports.add(port)
        elif system == "Windows":
            # for each device in supported devices found
            for d in sds:
                # find the port(s)
                com_ports = detect_windows_port(d)
                #print(f'com_ports:{com_ports}')
                # add all ports
                for com_port in com_ports:
                    ports.add(com_port)
    return ports


def detect_windows_port(sd):
    """detect if Windows port"""
    ports = set()

    if sd:
        system = platform.system()

        if system == "Windows":
            command = ('powershell.exe "[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8;'
                       'Get-PnpDevice -PresentOnly | Where-Object{ ($_.DeviceId -like ')
            command += f"'*{sd.usb_vendor_id_in_hex.upper()}*'"
            command += ')} | Format-List"'

            #print(f'command:{command}')
            _, sp_output = subprocess.getstatusoutput(command)
            #print(f'sp_output:{sp_output}')
            p = re.compile(r'\(COM(.*)\)')
            for x in p.findall(sp_output):
                #print(f'x:{x}')
                ports.add(f'COM{x}')
    return ports

Functions

def active_ports_on_supported_devices(sds)

Return a set of active ports based on the supplied supported devices

Expand source code
def active_ports_on_supported_devices(sds):
    """Return a set of active ports based on the supplied supported devices"""
    ports = set()
    baseports = set()
    system = platform.system()

    # figure out what possible base ports there are
    for d in sds:
        if system == "Linux":
            baseports.add(d.baseport_on_linux)
        elif system == "Darwin":
            baseports.add(d.baseport_on_mac)
        elif system == "Windows":
            baseports.add(d.baseport_on_windows)

    for bp in baseports:
        if system == "Linux":
            # see if we have any devices (ignoring any stderr output)
            command = f'ls -al /dev/{bp}* 2> /dev/null'
            #print(f'command:{command}')
            _, ls_output = subprocess.getstatusoutput(command)
            #print(f'ls_output:{ls_output}')
            # if we got output, there are ports
            if len(ls_output) > 0:
                #print('got output')
                # for each line of output
                lines = ls_output.split('\n')
                #print(f'lines:{lines}')
                for line in lines:
                    parts = line.split(' ')
                    #print(f'parts:{parts}')
                    port = parts[-1]
                    #print(f'port:{port}')
                    ports.add(port)
        elif system == "Darwin":
            # see if we have any devices (ignoring any stderr output)
            command = f'ls -al /dev/{bp}* 2> /dev/null'
            #print(f'command:{command}')
            _, ls_output = subprocess.getstatusoutput(command)
            #print(f'ls_output:{ls_output}')
            # if we got output, there are ports
            if len(ls_output) > 0:
                #print('got output')
                # for each line of output
                lines = ls_output.split('\n')
                #print(f'lines:{lines}')
                for line in lines:
                    parts = line.split(' ')
                    #print(f'parts:{parts}')
                    port = parts[-1]
                    #print(f'port:{port}')
                    ports.add(port)
        elif system == "Windows":
            # for each device in supported devices found
            for d in sds:
                # find the port(s)
                com_ports = detect_windows_port(d)
                #print(f'com_ports:{com_ports}')
                # add all ports
                for com_port in com_ports:
                    ports.add(com_port)
    return ports
def detect_windows_port(sd)

detect if Windows port

Expand source code
def detect_windows_port(sd):
    """detect if Windows port"""
    ports = set()

    if sd:
        system = platform.system()

        if system == "Windows":
            command = ('powershell.exe "[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8;'
                       'Get-PnpDevice -PresentOnly | Where-Object{ ($_.DeviceId -like ')
            command += f"'*{sd.usb_vendor_id_in_hex.upper()}*'"
            command += ')} | Format-List"'

            #print(f'command:{command}')
            _, sp_output = subprocess.getstatusoutput(command)
            #print(f'sp_output:{sp_output}')
            p = re.compile(r'\(COM(.*)\)')
            for x in p.findall(sp_output):
                #print(f'x:{x}')
                ports.add(f'COM{x}')
    return ports
def get_devices_with_vendor_id(vid)

Return a set of unique devices with the vendor id

Expand source code
def get_devices_with_vendor_id(vid):
    """Return a set of unique devices with the vendor id"""
    sd = set()
    for d in supported_devices:
        if d.usb_vendor_id_in_hex == vid:
            sd.add(d)
    return sd
def get_unique_vendor_ids()

Return a set of unique vendor ids

Expand source code
def get_unique_vendor_ids():
    """Return a set of unique vendor ids"""
    vids = set()
    for d in supported_devices:
        if d.usb_vendor_id_in_hex:
            vids.add(d.usb_vendor_id_in_hex)
    return vids

Classes

class SupportedDevice (name, version=None, for_firmware=None, device_class='esp32', baseport_on_linux=None, baseport_on_mac=None, baseport_on_windows='COM', usb_vendor_id_in_hex=None, usb_product_id_in_hex=None)

Devices supported on Meshtastic

constructor

Expand source code
class SupportedDevice():
    """Devices supported on Meshtastic"""

    def __init__(self, name, version=None, for_firmware=None, device_class="esp32",
                 baseport_on_linux=None, baseport_on_mac=None, baseport_on_windows="COM",
                 usb_vendor_id_in_hex=None, usb_product_id_in_hex=None):
        """ constructor """
        self.name = name
        self.version = version
        self.for_firmware = for_firmware
        self.device_class = device_class # could be "nrf52"

        # when you run "lsusb -d xxxx:" in linux
        self.usb_vendor_id_in_hex = usb_vendor_id_in_hex # store in lower case
        self.usb_product_id_in_hex = usb_product_id_in_hex # store in lower case

        self.baseport_on_linux = baseport_on_linux # ex: ttyUSB or ttyACM
        self.baseport_on_mac = baseport_on_mac
        self.baseport_on_windows = baseport_on_windows