diff --git a/.gitignore b/.gitignore index 9fefe27..72ebe49 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ tags # MKDocs build site/ + +# MicroPico +.micropico \ No newline at end of file diff --git a/docs/api.rst b/docs/api.rst index 25680ac..8aabc8e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -165,6 +165,15 @@ DigitalInputDevice :inherited-members: :members: +WiFi +---- + +.. autoclass:: WiFi + :show-inheritance: + :inherited-members: + :members: + + pinout ------ diff --git a/docs/changelog.rst b/docs/changelog.rst index 2481b1e..4be4509 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -3,6 +3,14 @@ Change log .. currentmodule:: picozero +0.7.0 - 2025-12-11 +----------- + ++ Introduced ``WiFi`` class for connecting to wireless networks on Pico W ++ Added ``brightness`` parameter to ``RGBLED`` class to control overall LED brightness ++ Added ``min_value`` and ``max_value`` parameters to ``PWMOutputDevice.pulse()`` and ``blink()`` methods to control brightness range ++ Updated documentation + 0.6.1 - 2025-11-28 ----------- diff --git a/docs/conf.py b/docs/conf.py index 7cc3dc7..456b670 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,7 +64,7 @@ def __getattr__(cls, name): author = "Raspberry Pi Foundation" # The full version, including alpha/beta/rc tags -release = "0.6.1" +release = "0.7.0" # -- General configuration --------------------------------------------------- diff --git a/docs/examples/wifi_connect.py b/docs/examples/wifi_connect.py new file mode 100644 index 0000000..6f83917 --- /dev/null +++ b/docs/examples/wifi_connect.py @@ -0,0 +1,8 @@ +""" +Simple WiFi connection example for Raspberry Pi Pico W +""" + +from picozero import WiFi + +wifi = WiFi() +wifi.connect("YourNetworkName", "YourPassword") diff --git a/docs/examples/wifi_info.py b/docs/examples/wifi_info.py new file mode 100644 index 0000000..bc70644 --- /dev/null +++ b/docs/examples/wifi_info.py @@ -0,0 +1,28 @@ +""" +Get detailed WiFi connection information +""" + +from picozero import WiFi + +wifi = WiFi() +wifi.connect("YourNetworkName", "YourPassword") + +# Get all connection info +info = wifi.info() +print("Network:", info["ssid"]) +print("IP:", info["ip"]) +print("Subnet:", info["subnet"]) +print("Gateway:", info["gateway"]) +print("DNS:", info["dns"]) +print("Signal:", info["signal"], "dBm") + +# Check signal strength +signal = wifi.signal_strength +if signal > -50: + print("Excellent signal!") +elif signal > -60: + print("Good signal") +elif signal > -70: + print("Fair signal") +else: + print("Weak signal") diff --git a/docs/examples/wifi_reconnect.py b/docs/examples/wifi_reconnect.py new file mode 100644 index 0000000..41ec5bf --- /dev/null +++ b/docs/examples/wifi_reconnect.py @@ -0,0 +1,29 @@ +""" +How to handle WiFi reconnection in a long-running program + +For programs that run continuously, you may want to check the connection +periodically and reconnect if it's been lost. +""" + +from picozero import WiFi +from time import sleep + +wifi = WiFi() +wifi.connect("YourNetworkName", "YourPassword") + +while True: + # Check if still connected + if not wifi.is_connected: + print("Connection lost! Reconnecting...") + try: + wifi.connect("YourNetworkName", "YourPassword") + print("Reconnected! IP:", wifi.ip) + except RuntimeError as e: + print("Reconnection failed:", e) + print("Will retry in 60 seconds...") + + # Do your work here + print("Signal strength:", wifi.signal_strength, "dBm") + + # Check again in 60 seconds + sleep(60) diff --git a/docs/recipes.rst b/docs/recipes.rst index 6288a24..ce5464f 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -335,3 +335,27 @@ Get the distance in metres from an ultrasonic distance sensor (HC-SR04): :alt: A diagram of the Raspberry Pi Pico connected to an HC-SR04 distance sensor. .. literalinclude:: examples/ultrasonic_distance_sensor.py + +WiFi (Pico W only) +------------------ + +Connect to a WiFi network +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Connect your Raspberry Pi Pico W to a wireless network using :class:`WiFi`: + +.. literalinclude:: examples/wifi_connect.py + +Get connection information +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get detailed information about the WiFi connection including IP address and signal strength: + +.. literalinclude:: examples/wifi_info.py + +Handle reconnection +~~~~~~~~~~~~~~~~~~~ + +For long-running programs, check the connection status and reconnect if needed: + +.. literalinclude:: examples/wifi_reconnect.py diff --git a/package.json b/package.json index 60ac58b..63d7080 100644 --- a/package.json +++ b/package.json @@ -5,5 +5,5 @@ ], "deps": [ ], - "version": "0.6.1" + "version": "0.7.0" } diff --git a/picozero/__init__.py b/picozero/__init__.py index 653b078..aa68fe8 100644 --- a/picozero/__init__.py +++ b/picozero/__init__.py @@ -1,6 +1,6 @@ __name__ = "picozero" __package__ = "picozero" -__version__ = "0.6.1" +__version__ = "0.7.0" __author__ = "Raspberry Pi Foundation" from .picozero import ( @@ -35,3 +35,10 @@ Thermistor, DistanceSensor, ) + +# WiFi is only available on Pico W, so import it from a separate module to avoid +# memory issues on regular Pico +try: + from .wifi import WiFi +except ImportError: + pass diff --git a/picozero/picozero.py b/picozero/picozero.py index 2e748bb..176047a 100644 --- a/picozero/picozero.py +++ b/picozero/picozero.py @@ -2637,3 +2637,4 @@ def max_distance(self): Returns the maximum distance that the sensor will measure in metres. """ return self._max_distance + diff --git a/picozero/wifi.py b/picozero/wifi.py new file mode 100644 index 0000000..0971f48 --- /dev/null +++ b/picozero/wifi.py @@ -0,0 +1,172 @@ +"""WiFi connectivity support for Raspberry Pi Pico W.""" + +from time import sleep + +try: + import network as _network_module + + class WiFi: + """ + Provides WiFi connectivity for Raspberry Pi Pico W. + + :param int timeout: + Default timeout in seconds for connection attempts. Defaults to 10. + """ + + def __init__(self, timeout=10): + self._network = _network_module + self._timeout = timeout + self._sta = None + + def connect(self, ssid, password, timeout=None): + """ + Connect to a WiFi network. + + :param str ssid: + The network name (SSID) to connect to. + + :param str password: + The network password. + + :param int timeout: + Connection timeout in seconds. If None, uses the default timeout + set during initialization. Defaults to None. + + :returns: + The IP address assigned to the Pico W. + + :raises RuntimeError: + If connection fails or times out. + """ + if timeout is None: + timeout = self._timeout + + self._sta = self._network.WLAN(self._network.STA_IF) + + if not self._sta.active(): + self._sta.active(True) + + if self._sta.isconnected(): + return self._sta.ifconfig()[0] + + self._sta.connect(ssid, password) + + # Wait for connection with timeout + elapsed = 0 + while not self._sta.isconnected() and elapsed < timeout: + sleep(0.2) + elapsed += 0.2 + + if not self._sta.isconnected(): + self._sta.active(False) + raise RuntimeError( + f"Failed to connect to '{ssid}' - check SSID and password" + ) + + return self._sta.ifconfig()[0] + + def disconnect(self): + """ + Disconnect from the WiFi network and deactivate the interface. + """ + if self._sta is not None: + self._sta.disconnect() + self._sta.active(False) + self._sta = None + + @property + def is_connected(self): + """ + Returns True if currently connected to a WiFi network. + """ + return self._sta is not None and self._sta.isconnected() + + @property + def ip(self): + """ + Returns the current IP address, or None if not connected. + """ + if self.is_connected: + return self._sta.ifconfig()[0] + return None + + @property + def subnet(self): + """ + Returns the subnet mask, or None if not connected. + """ + if self.is_connected: + return self._sta.ifconfig()[1] + return None + + @property + def gateway(self): + """ + Returns the gateway address, or None if not connected. + """ + if self.is_connected: + return self._sta.ifconfig()[2] + return None + + @property + def dns(self): + """ + Returns the DNS server address, or None if not connected. + """ + if self.is_connected: + return self._sta.ifconfig()[3] + return None + + @property + def signal_strength(self): + """ + Returns the WiFi signal strength (RSSI) in dBm, or None if not connected. + + Typical values: + - -30 dBm: Excellent signal + - -50 dBm: Very good signal + - -60 dBm: Good signal + - -70 dBm: Fair signal + - -80 dBm: Weak signal + - -90 dBm: Very weak signal + """ + if self.is_connected: + return self._sta.status('rssi') + return None + + @property + def ssid(self): + """ + Returns the SSID of the connected network, or None if not connected. + """ + if self.is_connected: + return self._sta.config('ssid') + return None + + def info(self): + """ + Returns a dictionary with connection information, or None if not connected. + + The dictionary includes: + - ip: IP address + - subnet: Subnet mask + - gateway: Gateway address + - dns: DNS server address + - ssid: Network name + - signal: Signal strength in dBm + """ + if not self.is_connected: + return None + + return { + 'ip': self.ip, + 'subnet': self.subnet, + 'gateway': self.gateway, + 'dns': self.dns, + 'ssid': self.ssid, + 'signal': self.signal_strength + } + +except ImportError: + # WiFi not available on regular Pico + pass diff --git a/setup.py b/setup.py index 12aa14d..8dff964 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ __project__ = "picozero" __packages__ = ["picozero"] __desc__ = "A beginner-friendly library for using common electronics components with the Raspberry Pi Pico. " -__version__ = "0.6.1" +__version__ = "0.7.0" __author__ = "Raspberry Pi Foundation" __author_email__ = "learning@raspberrypi.org" __license__ = "MIT"