Ir al contenido

← Punto de acceso WiFi por botón en un Raspberry PLC

Seguidores solares de dos ejesRaspberry PLC 21WiFiGPIOInfraestructura

Punto de acceso WiFi por botón en un Raspberry PLC — ejemplo completo

Convierte un pulsador en un punto de acceso WiFi temporal en un Raspberry PLC 21 con nmcli e interrupciones GPIO, para configurar en campo sin redes.

Programa completo y ejecutable para el Raspberry PLC 21 (wifi-access-point-button.py): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

#!/usr/bin/env python3
# -----------------------------------------------------------------------------
# COMPLETE EXAMPLE — WiFi access point activated by a physical button (nmcli)
#
# Device:    Raspberry PLC 21 (Industrial Shields)
# Based on:  dual-axis solar tracker project
#
# Requirements:
#   pip3 install RPi.GPIO
#   NetworkManager installed (nmcli) and service running
#   Run as root or with permissions over nmcli (systemd service)
#
# Logic:
#   A push button on PLC input I0.5 triggers a GPIO interrupt. The callback
#   brings up a WiFi hotspot with nmcli (profile "hotspot") for 15 minutes,
#   so the technician can connect with a phone/laptop to the tracker
#   dashboard in the field, without any network infrastructure. After the
#   timeout, the AP shuts down by itself so the network is not left exposed.
#   SSID and password are placeholders: replace them on each installation.
# -----------------------------------------------------------------------------

import subprocess
import threading
import time

import RPi.GPIO as GPIO

INT_GPIO    = 13          # BCM pin wired to PLC input I0.5
AP_SSID     = "AP_SSID"        # placeholder: hotspot SSID
AP_PASSWORD = "AP_PASSWORD"    # placeholder: WPA2 key (min 8 characters)
AP_IFACE    = "wlan0"
AP_TIMEOUT  = 15 * 60     # 15 minutes of AP uptime

shutdown_timer = None     # shutdown timer currently running


def nmcli(*args, timeout=15):
    """Runs nmcli and returns the CompletedProcess (no exception on failure)."""
    return subprocess.run(["nmcli", *args], capture_output=True,
                          text=True, timeout=timeout)


def connection_exists(name):
    """True if a connection profile with that name already exists."""
    res = nmcli("-t", "-f", "NAME", "connection", "show")
    return name in res.stdout.splitlines()


def create_connection(name):
    """Creates the WPA2 hotspot profile with shared IP (AP mode)."""
    nmcli("connection", "add", "type", "wifi", "ifname", AP_IFACE,
          "con-name", name, "autoconnect", "no", "ssid", AP_SSID)
    nmcli("connection", "modify", name,
          "802-11-wireless.mode", "ap",
          "802-11-wireless.band", "bg",
          "ipv4.method", "shared",
          "wifi-sec.key-mgmt", "wpa-psk",
          "wifi-sec.psk", AP_PASSWORD)
    print(f"Profile '{name}' created (SSID {AP_SSID})")


def start_ap():
    """Activates the hotspot and schedules its automatic shutdown."""
    global shutdown_timer
    if not connection_exists("hotspot"):
        create_connection("hotspot")
    res = nmcli("connection", "up", "hotspot", timeout=15)
    if res.returncode == 0:
        print(f"AP active for {AP_TIMEOUT // 60} min")
    else:
        print(f"Error bringing up the AP: {res.stderr.strip()}")
        return
    # Restart the timer if the button is pressed while the AP is already up.
    if shutdown_timer:
        shutdown_timer.cancel()
    shutdown_timer = threading.Timer(AP_TIMEOUT, stop_ap)
    shutdown_timer.daemon = True
    shutdown_timer.start()


def stop_ap():
    """Shuts down the hotspot (end of the field configuration window)."""
    nmcli("connection", "down", "hotspot")
    print("AP down: end of configuration window")


def int_activated_callback(channel):
    """Button interrupt: simple debounce + AP startup."""
    time.sleep(0.05)                      # debounce
    if GPIO.input(INT_GPIO) == GPIO.LOW:  # confirm a real press
        print("Button pressed: bringing up access point")
        start_ap()


def main():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(INT_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.add_event_detect(INT_GPIO, GPIO.FALLING,
                          callback=int_activated_callback, bouncetime=300)
    print(f"Waiting for a press on I0.5 (GPIO {INT_GPIO})...")
    try:
        while True:
            time.sleep(1)                 # the interrupt does the work
    except KeyboardInterrupt:
        pass
    finally:
        stop_ap()
        GPIO.cleanup()
        print("GPIO released")


if __name__ == '__main__':
    main()
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales