diff --git a/adafruit_esp32spi/adafruit_esp32spi.py b/adafruit_esp32spi/adafruit_esp32spi.py index f93a0f7..2b113d8 100644 --- a/adafruit_esp32spi/adafruit_esp32spi.py +++ b/adafruit_esp32spi/adafruit_esp32spi.py @@ -37,6 +37,9 @@ _SET_NET_CMD = const(0x10) _SET_PASSPHRASE_CMD = const(0x11) +_SET_IP_CONFIG = const(0x14) +_SET_DNS_CONFIG = const(0x15) +_SET_HOSTNAME = const(0x16) _SET_AP_NET_CMD = const(0x18) _SET_AP_PASSPHRASE_CMD = const(0x19) _SET_DEBUG_CMD = const(0x1A) @@ -405,6 +408,46 @@ def scan_networks(self): return APs return None + def set_ip_config(self, ip_address, gateway, mask="255.255.255.0"): + """Tells the ESP32 to set ip, gateway and network mask b"\xFF" + + :param str ip_address: IP address (as a string). + :param str gateway: Gateway (as a string). + :param str mask: Mask, defaults to 255.255.255.0 (as a string). + """ + resp = self._send_command_get_response( + _SET_IP_CONFIG, + params=[ + b"\x00", + self.unpretty_ip(ip_address), + self.unpretty_ip(gateway), + self.unpretty_ip(mask), + ], + sent_param_len_16=False, + ) + return resp + + def set_dns_config(self, dns1, dns2): + """Tells the ESP32 to set DNS + + :param str dns1: DNS server 1 IP as a string. + :param str dns2: DNS server 2 IP as a string. + """ + resp = self._send_command_get_response( + _SET_DNS_CONFIG, [b"\x00", self.unpretty_ip(dns1), self.unpretty_ip(dns2)] + ) + if resp[0][0] != 1: + raise RuntimeError("Failed to set dns with esp32") + + def set_hostname(self, hostname): + """Tells the ESP32 to set hostname for DHCP. + + :param str hostname: The new host name. + """ + resp = self._send_command_get_response(_SET_HOSTNAME, [hostname.encode()]) + if resp[0][0] != 1: + raise RuntimeError("Failed to set hostname with esp32") + def wifi_set_network(self, ssid): """Tells the ESP32 to set the access point to the given ssid""" resp = self._send_command_get_response(_SET_NET_CMD, [ssid]) @@ -518,8 +561,7 @@ def connect(self, secrets): self.connect_AP(secrets["ssid"], secrets["password"]) def connect_AP(self, ssid, password, timeout_s=10): # pylint: disable=invalid-name - """ - Connect to an access point with given name and password. + """Connect to an access point with given name and password. Will wait until specified timeout seconds and return on success or raise an exception on failure. @@ -552,8 +594,7 @@ def connect_AP(self, ssid, password, timeout_s=10): # pylint: disable=invalid-n def create_AP( self, ssid, password, channel=1, timeout=10 ): # pylint: disable=invalid-name - """ - Create an access point with the given name, password, and channel. + """Create an access point with the given name, password, and channel. Will wait until specified timeout seconds and return on success or raise an exception on failure. @@ -814,8 +855,7 @@ def set_esp_debug(self, enabled): raise RuntimeError("Failed to set debug mode") def set_pin_mode(self, pin, mode): - """ - Set the io mode for a GPIO pin. + """Set the io mode for a GPIO pin. :param int pin: ESP32 GPIO pin to set. :param value: direction for pin, digitalio.Direction or integer (0=input, 1=output). @@ -831,8 +871,7 @@ def set_pin_mode(self, pin, mode): raise RuntimeError("Failed to set pin mode") def set_digital_write(self, pin, value): - """ - Set the digital output value of pin. + """Set the digital output value of pin. :param int pin: ESP32 GPIO pin to write to. :param bool value: Value for the pin. @@ -844,8 +883,7 @@ def set_digital_write(self, pin, value): raise RuntimeError("Failed to write to pin") def set_analog_write(self, pin, analog_value): - """ - Set the analog output value of pin, using PWM. + """Set the analog output value of pin, using PWM. :param int pin: ESP32 GPIO pin to write to. :param float value: 0=off 1.0=full on @@ -858,8 +896,7 @@ def set_analog_write(self, pin, analog_value): raise RuntimeError("Failed to write to pin") def set_digital_read(self, pin): - """ - Get the digital input value of pin. Returns the boolean value of the pin. + """Get the digital input value of pin. Returns the boolean value of the pin. :param int pin: ESP32 GPIO pin to read from. """ @@ -877,8 +914,7 @@ def set_digital_read(self, pin): ) def set_analog_read(self, pin, atten=ADC_ATTEN_DB_11): - """ - Get the analog input value of pin. Returns an int between 0 and 65536. + """Get the analog input value of pin. Returns an int between 0 and 65536. :param int pin: ESP32 GPIO pin to read from. :param int atten: attenuation constant @@ -914,6 +950,7 @@ def get_time(self): def set_certificate(self, client_certificate): """Sets client certificate. Must be called BEFORE a network connection is established. + :param str client_certificate: User-provided .PEM certificate up to 1300 bytes. """ if self._debug: @@ -936,6 +973,7 @@ def set_certificate(self, client_certificate): def set_private_key(self, private_key): """Sets private key. Must be called BEFORE a network connection is established. + :param str private_key: User-provided .PEM file up to 1700 bytes. """ if self._debug: diff --git a/adafruit_esp32spi/digitalio.py b/adafruit_esp32spi/digitalio.py index d825f70..c935794 100755 --- a/adafruit_esp32spi/digitalio.py +++ b/adafruit_esp32spi/digitalio.py @@ -50,6 +50,7 @@ def __init__(self, esp_pin, esp): def init(self, mode=IN): """Initalizes a pre-defined pin. + :param mode: Pin mode (IN, OUT, LOW, HIGH). Defaults to IN. """ if mode is not None: @@ -64,6 +65,7 @@ def init(self, mode=IN): def value(self, val=None): """Sets ESP32 Pin GPIO output mode. + :param val: Pin output level (LOW, HIGH) """ if val is not None: @@ -133,6 +135,7 @@ def deinit(self): def switch_to_output(self, value=False, drive_mode=DriveMode.PUSH_PULL): """Set the drive mode and value and then switch to writing out digital values. + :param bool value: Default mode to set upon switching. :param DriveMode drive_mode: Drive mode for the output. """ @@ -142,6 +145,7 @@ def switch_to_output(self, value=False, drive_mode=DriveMode.PUSH_PULL): def switch_to_input(self, pull=None): """Sets the pull and then switch to read in digital values. + :param Pull pull: Pull configuration for the input. """ raise NotImplementedError( @@ -156,6 +160,7 @@ def direction(self): @direction.setter def direction(self, pin_dir): """Sets the direction of the pin. + :param Direction dir: Pin direction (Direction.OUTPUT or Direction.INPUT) """ self.__direction = pin_dir @@ -176,6 +181,7 @@ def value(self): @value.setter def value(self, val): """Sets the digital logic level of the pin. + :param type value: Pin logic level. :param int value: Pin logic level. 1 is logic high, 0 is logic low. :param bool value: Pin logic level. True is logic high, False is logic low. @@ -195,8 +201,9 @@ def drive_mode(self): @drive_mode.setter def drive_mode(self, mode): """Sets the pin drive mode. + :param DriveMode mode: Defines the drive mode when outputting digital values. - Either PUSH_PULL or OPEN_DRAIN + Either PUSH_PULL or OPEN_DRAIN """ if mode is DriveMode.OPEN_DRAIN: raise NotImplementedError( diff --git a/examples/esp32spi_ipconfig.py b/examples/esp32spi_ipconfig.py new file mode 100644 index 0000000..01f01c8 --- /dev/null +++ b/examples/esp32spi_ipconfig.py @@ -0,0 +1,89 @@ +# SPDX-FileCopyrightText: 2019 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time +import board +import busio +from digitalio import DigitalInOut +import adafruit_esp32spi.adafruit_esp32spi_socket as socket +from adafruit_esp32spi import adafruit_esp32spi + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +HOSTNAME = "esp32-spi-hostname-test" + +IP_ADDRESS = "192.168.1.111" +GATEWAY_ADDRESS = "192.168.1.1" +SUBNET_MASK = "255.255.255.0" + +UDP_IN_ADDR = "192.168.1.1" +UDP_IN_PORT = 5500 + +UDP_TIMEOUT = 20 + +esp32_cs = DigitalInOut(board.CS1) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1) + +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) +socket.set_interface(esp) + +s_in = socket.socket(type=socket.SOCK_DGRAM) +s_in.settimeout(UDP_TIMEOUT) +print("set hostname:", HOSTNAME) +esp.set_hostname(HOSTNAME) + +if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: + print("ESP32 found and in idle mode") +print("Firmware vers.", esp.firmware_version) +print("MAC addr:", [hex(i) for i in esp.MAC_address]) + +print("Connecting to AP...") +while not esp.is_connected: + try: + esp.connect_AP(secrets["ssid"], secrets["password"]) + except RuntimeError as e: + print("could not connect to AP, retrying: ", e) + continue +print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi) +ip1 = esp.ip_address + +print("set ip dns") +esp.set_dns_config("192.168.1.1", "8.8.8.8") + +print("set ip config") +esp.set_ip_config(IP_ADDRESS, GATEWAY_ADDRESS, SUBNET_MASK) + +time.sleep(1) +ip2 = esp.ip_address + +time.sleep(1) +info = esp.network_data +print( + "get network_data: ", + esp.pretty_ip(info["ip_addr"]), + esp.pretty_ip(info["gateway"]), + esp.pretty_ip(info["netmask"]), +) + +IP_ADDR = esp.pretty_ip(esp.ip_address) +print("ip:", IP_ADDR) +print("My IP address is", esp.pretty_ip(esp.ip_address)) +print("udp in addr: ", UDP_IN_ADDR, UDP_IN_PORT) + +socketaddr_udp_in = socket.getaddrinfo(UDP_IN_ADDR, UDP_IN_PORT)[0][4] +s_in.connect(socketaddr_udp_in, conntype=esp.UDP_MODE) +print("connected local UDP") + +while True: + data = s_in.recv(1205) + if len(data) >= 1: + data = data.decode("utf-8") + print(len(data), data)