Pico wireless pack fetching data from web?

Hello Fellow Buccaneers,

The bug has definitely bitten me, I bought a Pi six months ago to run the pihole ad-blocking software, and now I have 3 Pis, 3 Picos, and an Adafruit Metro ESP32 Express to play with.

My question is about the Pico Wireless Pack. I’ve got the rgb_http.py example running and can set the led colours from my phone, so far so good and I’ve seen a few references to that on here.

Has anyone got the cheerlights.py example to work fetching data? It gets so far then nothing.
It connects to the wireless and gets as far as line 47 - picowireless.send_data(client_sock, http_request) but then it sits there never receiving any data and I have to break out of the routine.
I know it gets past line 47 as I added a print statement to confirm.
I even set up Apache on one of my local Pis to test retrieving from there and still nothing, not even a request in the Apache log files.

I’m assuming the person that wrote the code has success with it, I’d just like to know if anybody else has.

It’s nice to have this community to ask,

Chris.

I just loaded it onto my board there and it seems to connect to the thingspeak API fine and sets an LED. Do you know how far past line 47 it gets? Are you runnin the latest PImoroni Micropython firmware?

I started with version 0.1.8 but now I’m on 0.2.1 with still no joy, I even nuked it before putting on the latest version.
The picowireless.send_data(client_sock, http_request) request is made then it goes into the loop below which it never comes out of as no data seems to come back.

while True:
avail_length = picowireless.avail_data(client_sock)
if avail_length > 0:
break

I can’t even try another Pico because both boards are well and truly plugged into a Pico Omnibus.

Any other ideas to try?

Sorry, I honestly don’t know, but it sounds like your board isn’t getting a response from the thingspeak API. Any odds something on your home network would be blocking that?

both boards are well and truly plugged into a Pico Omnibus

You can insert a lever (pencil, pen or screw driver) slightly into the gap and slowly, gently lever them apart one corner at a time and 1 mm at a time. Do it slowly and you will not bend the pins. Use the outside edges of the wireless to avoid underside components. The Pico has nothing on the underside.

I get the same halt as you. I think we have to set up our own ThingSpeak channel - which is quite a lot of work as I’ve not done it before. We then write to the channel and the Pico wireless notices and 'does its thing"!

A tutorial , or even a hint, would have been helpful.

You can get a free account with ThingSpeak . You need a Mathswork account.

Why OH Why do they not help you get started?

Not quite as difficult. See here: CheerLights API – CheerLights IoT
Unfortunately, I’m not a twitter user, but it appears you #Cheerlights, RED, #FF0000 or something similar in a tweet and the colours should change.

Do I really want a Twitter account?
##############################################
Joined Twitter but still no change on RGB LED.

Has anyone got this to work?

I’ve had some success with this over the weekend using CircuitPython, but now I really must do some real work.
Will write up what I did later this evening.

That would be great. Can we see the code?

Of course Tony, happy to, thanks for the pointer to the Cheerlights page, quite a nice project.

The inspiration for what I did is here:
Tom’s Hardware Pimoroni Pico Wireless

I borrowed sections from this page to get the Pico prepared (see steps below).

The steps I went through:

  1. The Installing CircuitPython on Raspberry Pi Pico section of the page to get the Pico installed with CircuitPython and the relevant libraries.

  2. The Creating a secrets file for wifi login section of the page to get wifi set up on the Pico.

I then took the script from the page that talks to Weather API and modified it to talk to the Cheerlights API instead. The Cheerlights API does not require any kind of registration to access it. The script uses the API method that returns the hexadecimal value of the last colour tweeted.

The “Getting Started” section of the Pimoroni product page gave me the pin changes required in the code.

The code itself is below, it attempts to retrieve the Cheerlights colour value every fifteen seconds and lights up the LEDs on the Pico Wireless to match. It doesn’t trap for all errors yet but will flash the red LED rapidly if it fails to make a connection. I used the mu editor to write the script and run the code on the Pico.

import board
import busio
from digitalio import DigitalInOut
import adafruit_requests as requests
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
from secrets import secrets
import time
import math

print("Using Pico wireless pack to get http data")
REQUEST_URL = "http://api.thingspeak.com/channels/1417/field/2/last.txt"

#Set the pins for controlling the ESP32
esp32_cs = DigitalInOut(board.GP7)
esp32_ready = DigitalInOut(board.GP10)
esp32_reset = DigitalInOut(board.GP11)

#Initialise the SPI bus on the Pico.
spi = busio.SPI(board.GP18, board.GP19, board.GP16)
#Initialise the ESP32 as a device on the SPI bus.
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

requests.set_socket(socket, esp)

while True:
    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("Local IP address: " + esp.pretty_ip(esp.ip_address))


    # Turn off the Pico Wireless LEDs
    esp.set_analog_write(25, 1)
    esp.set_analog_write(26, 1)
    esp.set_analog_write(27, 1)

    print("Fetching data from " + REQUEST_URL)
    try:
        r = requests.get(REQUEST_URL)
        print("HTTP response code: " + str(r.status_code))
        print("-" * 40)
        print("Response: " + str(r.text))
        print("-" * 40)
        r.close()
        # Parse the response string into rgb hex values.
        red = str(r.text)[1:3]
        green = str(r.text)[3:5]
        blue = str(r.text)[5:]

        # Convert the hex values to integer values.
        red = (int(red, 16))
        green = (int(green, 16))
        blue = (int(blue, 16))

        # Invert the rgb values as the Pico wireless leds are on when low, off when high.
        # The match.fabs function always returns a positive value.
        red = math.fabs(red-255)
        green = math.fabs(green-255)
        blue = math.fabs(blue-255)

        # Light the leds
        esp.set_analog_write(25, red/255)
        esp.set_analog_write(26, green/255)
        esp.set_analog_write(27, blue/255)

    # Flash the led if an error occurs with the http request
    except RuntimeError as e2:
        print("http request error: ", e2)
        for i in range(0,10):
            esp.set_analog_write(25,0)
            time.sleep(0.2)
            esp.set_analog_write(25,1)
            time.sleep(0.2)
            continue

    time.sleep(15)

Once running it should always set the led to a colour, Cheerlights are never off, so you can either enjoy the colour changes of those people tweeting “Cheerlights” around the world, or have a go yourself.

It feels like there’s a lot here, it was easier to just do than to write up.

Hope this helps,

Chris.

Thank you for sharing. I will give it a try.

I’m a bit disappointed that you had to move to CircuitPython to get it to work. I feel that examples from the manufacturer should really work - straight out of the box. Pimoroni only supply MicroPython so I expected the board to work with MicroPython and the example.

I think Adafruit are being left to do all the heavy lifting.

The Cheerlights MicroPython example is working fine for me, with the most recent custom UF2. You shouldn’t need to sign up for any accounts anywhere, just plug your wifi details into the code in Thonny (they’re case sensitive). Possibly worth checking if your router’s security settings are blocking the external connection (or if you have an overzealous Pi-Hole running?)

Do you have multiple boards plugged into your Pico? I found Wireless stopped connecting when I had a Display connected to the same Pico.

I have a just a Pico and wireless plugged into a Pico Decker - no other connections.
Re-installed latest Full Pimoroni UF2
Downloaded the example.

Logs onto site but no info downloads.

Added a counter

while True:
    if picowireless.get_connection_status() == 3:
        break
print("Connected!")
count = 0
# Get our own local IP!
my_ip = picowireless.get_ip_address()
print("Local IP: {}.{}.{}.{}".format(*my_ip))

# Resolve and cache the IP address
picowireless.set_dns(USE_DNS)
http_address = picowireless.get_host_by_name(HTTP_REQUEST_HOST)
print("Resolved {} to {}.{}.{}.{}".format(HTTP_REQUEST_HOST, *http_address))

client_sock = picowireless.get_socket()


def handler(head, body):
    if head["Status"] == "200 OK":
        color = body[1:]
        r = int(color[0:2], 16)
        g = int(color[2:4], 16)
        b = int(color[4:6], 16)
        picowireless.set_led(r, g, b)
        print("Set LED to {} {} {}".format(r, g, b))
    else:
        print("Error: {}".format(head["Status"]))


while True:
    print(count)
    http_request(client_sock, http_address, HTTP_PORT, HTTP_REQUEST_HOST, HTTP_REQUEST_PATH, handler)
    count = count + 1
    time.sleep(60.0)

Still no change in colour of the LED - just its faint rendering of OFF and this stuck loop in the monitor window:

MicroPython v1.15 on 2021-05-20; Raspberry Pi Pico with RP2040

Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
Connecting to VM051184-2G...
Connected!
Local IP: 192.168.0.9
Resolved api.thingspeak.com to 54.88.253.164
0
Connecting to 54.88.253.164:80...
Connected!

I’m still stuck…

I’m also a bit concerned that the wireless and Display cannot be used together. I bought the wireless to download things from the net to be displayed on the screen - like a weather forecast!

Do you have multiple boards plugged into your Pico? I found Wireless stopped connecting when I had a Display connected to the same Pico.

So after a bit of fiddling the Wireless has weird issues if the Pico Display isn’t initialised. If you initialise it the Wireless seems to work fine (the RGB demo does at least) but the display doesn’t work. I think that’s because both boards are trying to use physical pin 21 (LCD_DC for the screen and MISO for the Wireless).

I’m going to be honest, I know that writing most of the underlying code in C and just having a Python wrapper (is that the right term?) on top of it might cut down on work for Gadgetoid and ZodisInfuser, but it does make it harder to tinker with when trying to work stuff out like this, at least for people like me who aren’t so hot on C and how C and Python interact.

I normally check for pin clashes before buying a new board, unfortunately the pinout was not available on the first day the board was available. Wireless a bit of a dead duck at the moment.

Might be worth trying this tweak, which adds a 5sec timeout to http_request.

Perhaps the first request is failing for some reason, but subsequent requests may work.

The example and latest firmware still work locally for me.

(At time point I’d like to sweep all the implementation details of HTTP, connecting, etc under the rug and handle all the weird edge cases/failures better, wireless is… hard…)

import time
import picowireless
from micropython import const

WIFI_SSID = "gadgetoidsecretlair"
WIFI_PASS = "hunter2"

CLOUDFLARE_DNS = (1, 1, 1, 1)
GOOGLE_DNS = (8, 8, 8, 8)
USE_DNS = CLOUDFLARE_DNS

TCP_MODE = const(0)
HTTP_REQUEST_DELAY = const(30)
HTTP_PORT = 80
HTTP_REQUEST_HOST = "api.thingspeak.com"
HTTP_REQUEST_PATH = "/channels/1417/field/2/last.txt"


def connect(host_address, port, client_sock, timeout=1000):
    picowireless.client_start(host_address, port, client_sock, TCP_MODE)

    t_start = time.time()
    timeout /= 1000.0

    while time.time() - t_start < timeout:
        state = picowireless.get_client_state(client_sock)
        if state == 4:
            return True
        time.sleep(1.0)

    return False


def http_request(client_sock, host_address, port, request_host, request_path, handler, timeout=5000):
    print("Connecting to {1}.{2}.{3}.{4}:{0}...".format(port, *host_address))
    if not connect(host_address, port, client_sock):
        print("Connection failed!")
        return False
    print("Connected!")

    http_request = """GET {} HTTP/1.1
Host: {}
Connection: close

""".format(request_path, request_host).replace("\n", "\r\n")

    picowireless.send_data(client_sock, http_request)

    t_start = time.time()

    while True:
        if time.time() - t_start > timeout:
            picowireless.client_stop(client_sock)
            print("HTTP request to {}:{} timed out...".format(host_address, port))
            return False

        avail_length = picowireless.avail_data(client_sock)
        if avail_length > 0:
            break

    print("Got response: {} bytes".format(avail_length))

    response = b""

    while len(response) < avail_length:
        data = picowireless.get_data_buf(client_sock)
        response += data

    response = response.decode("utf-8")

    head, body = response.split("\r\n\r\n", 1)
    dhead = {}

    for line in head.split("\r\n")[1:]:
        key, value = line.split(": ", 1)
        dhead[key] = value

    handler(dhead, body)

    picowireless.client_stop(client_sock)


picowireless.init()

print("Connecting to {}...".format(WIFI_SSID))
picowireless.wifi_set_passphrase(WIFI_SSID, WIFI_PASS)

while True:
    if picowireless.get_connection_status() == 3:
        break
print("Connected!")

# Get our own local IP!
my_ip = picowireless.get_ip_address()
print("Local IP: {}.{}.{}.{}".format(*my_ip))

# Resolve and cache the IP address
picowireless.set_dns(USE_DNS)
http_address = picowireless.get_host_by_name(HTTP_REQUEST_HOST)
print("Resolved {} to {}.{}.{}.{}".format(HTTP_REQUEST_HOST, *http_address))

client_sock = picowireless.get_socket()


def handler(head, body):
    if head["Status"] == "200 OK":
        color = body[1:]
        r = int(color[0:2], 16)
        g = int(color[2:4], 16)
        b = int(color[4:6], 16)
        picowireless.set_led(r, g, b)
        print("Set LED to {} {} {}".format(r, g, b))
    else:
        print("Error: {}".format(head["Status"]))


while True:
    http_request(client_sock, http_address, HTTP_PORT, HTTP_REQUEST_HOST, HTTP_REQUEST_PATH, handler)
    time.sleep(60.0)


I’d just put Micropython back on the Pico to start all over again and your post appeared Gadgetoid.
It works, thanks for your efforts with this!!!
I can’t say I haven’t learned anything from the experience, CircuitPython, http headers, and even back into Wireshark to trace the packets. All to light an LED via the internet.

Going for a lie down now before starting on the next challenge this “hobby” throws at me :-)

Once again thanks,

Chris.

Gadgetoid - Thank you that works. I will study the code to understand the differences.

I’m a person who only bought a smartphone for its camera, so, could someone tell me what to tweet to that I can check the colour changes? Can’t be waiting someone else to start testing and I’ve only seen green and magenta so far.

If you add a print line here:

   while len(response) < avail_length:
        data = picowireless.get_data_buf(client_sock)
        response += data

    response = response.decode("utf-8")
    print(response)           # <=============== ADDED HERE ==========

    head, body = response.split("\r\n\r\n", 1)
    dhead = {}

You get a much greater output from each 60 second download:

Connecting to 54.210.227.170:80…
Connected!
Got response: 646 bytes
HTTP/1.1 200 OK
Date: Sat, 05 Jun 2021 09:21:08 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 7
Connection: close
Status: 200 OK
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS, DELETE, PATCH
Access-Control-Allow-Headers: origin, content-type, X-Requested-With
Access-Control-Max-Age: 1800
ETag: W/“5b723c67ea8a28df5aa2267333926aa2”
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 5e203667-6765-4084-88ab-d5d1cb06bfb2
X-Runtime: 0.005862
X-Powered-By: Phusion Passenger 4.0.57
Server: nginx/1.9.3 + Phusion Passenger 4.0.57

#FFA500
Set LED to 255 165 0

This includes the day, date and time already split up. - Interesting - It should be easy to extract and build a clock without the expense of Real Time Clock hardware.

Tweet something like this Tony.


The list of available colours is at the bottom of this page.

Great - It worked. We are learning all the time and Twitter is useful!