Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

My adventure with the Enviro Urban #173

Open
mrexodia opened this issue Apr 25, 2023 · 10 comments
Open

My adventure with the Enviro Urban #173

mrexodia opened this issue Apr 25, 2023 · 10 comments

Comments

@mrexodia
Copy link

mrexodia commented Apr 25, 2023

This is just some rough notes of some issues I encountered with the Urban and how I managed to resolve them. I never worked with the Pico and only a little with embedded devices in general, so this is just my perspective. Feel free to split this into multiple issues if that's more appropriate.

Provisioning

At first I used a WLAN USB dongle to perform the provisioning process. The wizard was working fine, but it always froze on the last step. This could be happening because I have another ethernet connection, but the only way for me to fix this was to use another device for the provisioning.

Troubleshooting

This was immediately quite discouraging and the Troubleshooting guide was not helpful for this. The suggestions were:

  1. Try again (which I did 5+ times)
  2. Look at config.py: I was not able to locate this file. It's not specified anywhere that you should use Thonny to do this. I never worked with Micropython and I assumed a volume would appear similar to the firmware upgrade.

It's also not mentioned anywhere you can use Putty or any other serial port tool to view the logs live (Thonny per default interrupts execution and you have to know to select Run -> Send EOF/Soft reboot to see the logs. The log.txt is not automatically reloaded and it's very frustrating to work with.

Firmware v0.0.9

I figured my problems might be fixed with the latest firmware, so I upgraded to 0.0.9. Unfortunately this firmware is completely broken and when you connect USB I was getting 'failed to get descriptor' errors and the COM port was no longer visible. So I had to downgrade to 0.0.8, which at least connected to Thonny properly.

In the end I flashed the latest version of https://github.com/pimoroni/pimoroni-pico (-enviro) on my device and manually copied the latest files from the master branch.

WLAN debugging

There seems to be something strange going on with the WLAN. Most likely it's related to the battery reading (although this is a strange thing). I decided to try on a different (new) Pico W and see if I could get a reliable connection. After a lot of messing around I ended up with the following function that seems to work and reliably handle errors:

def reconnect_wifi(ssid, password, country):
    import time
    import network
    import math
    import rp2
    import ubinascii
    
    start_ms = time.ticks_ms()

    # Set country
    rp2.country(country)

    # Reference: https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
    CYW43_LINK_DOWN = 0
    CYW43_LINK_JOIN = 1
    CYW43_LINK_NOIP = 2
    CYW43_LINK_UP = 3
    CYW43_LINK_FAIL = -1
    CYW43_LINK_NONET = -2
    CYW43_LINK_BADAUTH = -3

    status_names = {
        CYW43_LINK_DOWN: "Link is down",
        CYW43_LINK_JOIN: "Connected to wifi",
        CYW43_LINK_NOIP: "Connected to wifi, but no IP address",
        CYW43_LINK_UP: "Connect to wifi with an IP address",
        CYW43_LINK_FAIL: "Connection failed",
        CYW43_LINK_NONET: "No matching SSID found (could be out of range, or down)",
        CYW43_LINK_BADAUTH: "Authenticatation failure",
    }

    wlan = network.WLAN(network.STA_IF)

    def wlog(message):
        print(f"[WLAN] {message}")

    def dump_status():
        status = wlan.status()
        wlog(f"active: {1 if wlan.active() else 0}, status: {status} ({status_names[status]})")
        return status

    def wait_status(expected_status, *, timeout=10, tick_sleep=0.5):
        for i in range(math.ceil(timeout / tick_sleep)):
            time.sleep(tick_sleep)
            status = dump_status()
            if status == expected_status:
                return True
            if status < 0:
                raise Exception(status_names[status])
        return False

    # Disable power saving mode
    wlan.active(True)
    wlan.config(pm=0xa11140)

    # Print MAC
    mac = ubinascii.hexlify(wlan.config('mac'),':').decode()
    wlog("MAC: " + mac)
    
    # Disconnect when necessary
    status = dump_status()
    if status >= CYW43_LINK_JOIN and status <= CYW43_LINK_UP:
        wlog("Disconnecting...")
        wlan.disconnect()
        try:
            wait_status(CYW43_LINK_DOWN)
        except Exception as x:
            raise Exception(f"Failed to disconnect: {x}")
    wlog("Ready for connection!")

    # Connect to our AP
    wlog(f"Connecting to SSID {ssid} (password: {password})...")
    wlan.connect(ssid, password)
    try:
        wait_status(CYW43_LINK_UP)
    except Exception as x:
        raise Exception(f"Failed to connect to SSID {ssid} (password: {password}): {x}")
    wlog("Connected successfully!")

    ip, subnet, gateway, dns = wlan.ifconfig()
    wlog(f"IP: {ip}, Subnet: {subnet}, Gateway: {gateway}, DNS: {dns}")
    
    elapsed_ms = time.ticks_ms() - start_ms
    wlog(f"Elapsed: {elapsed_ms}ms")
    return elapsed_ms

Replacing the body of connect_to_wifi with the following seems to have fixed all the issues I encountered:

def connect_to_wifi():
  try:
    logging.info(f"> connecting to wifi network '{config.wifi_ssid}'")
    elapsed_ms = reconnect_wifi(config.wifi_ssid, config.wifi_password, config.wifi_country)
    # a slow connection time will drain the battery faster and may
    # indicate a poor quality connection
    seconds_to_connect = elapsed_ms / 1000
    if seconds_to_connect > 5:
      logging.warn("  - took", seconds_to_connect, "seconds to connect to wifi")
    return True
  except Exception as x:
    logging.error(f"! {x}")
    return False

I added the wifi_country variable to config.py as well.

Misc

For debugging this snippet is helpful:

from machine import Pin
led = Pin("LED", Pin.OUT)
led.on()
input("Press enter to continue...")
led.off()

I would also suggest adding a guide with https://pipedream.com/requestbin for the HTTP request. This was by far the easiest way to test if things are working for me.

It also seems like things are not designed to work on USB power. Rebooting seems unnecessary and you're only causing connection loss issues by not properly disconnecting the wifi. I added:

  finally:
    # Disconnect wifi
    import network
    print("[WLAN] Disconnecting after upload")
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.disconnect()
    wlan.active(False)

At the end of upload_readings, which seems to work fine.

@sjefferson99
Copy link
Contributor

I don't have any issues with wifi and provisioning, but I've made a local branch of the code suggested just to test it out for general use and it does look to be tidier code. Also for fun, I've tried switching back to the battery connector instead of USB on the off chance the wifi disconnect code does anything to help the board crashes I reliably see on battery power but not USB.

The branch is here if anyone else is suffering wifi issues and wants to test this code out by simply copying files: https://github.com/sjefferson99/enviro/tree/wifi-improvements

I haven't tested loading the v0.0.9 release firmware, but I did experience significant memory errors on the pimoroni-enviro firmware v1.19.17 and .18 and have been running stable on v1.19.16 for a few weeks now running main branch code plus my various pull requests. I haven't tried v1.20.0 yet

@sjefferson99
Copy link
Contributor

It's early days yet, but where my board consistently crashed after a couple of hours on battery power (workaround was to use USB), it has run for 12 hours+ without issue on battery power with the new network code. There seems to be something weird to do with wifi and battery power and sharing of pins and upstream code from other issues, but potentially properly closing the wifi connection as introduced here makes this more stable?

@mrexodia
Copy link
Author

Yeah I’m also running it (although on USB power) and everything seems stable now. I did realize today that there is no sleep after the disconnect, so if the device goes to sleep quickly it might not disconnect properly…

@sjefferson99
Copy link
Contributor

My next large chunk of work is to see if it can be easily adjusted to run on mains power and sample much more frequently (4 Hz would be ideal) and bin the power down altogether to get much better gust and direction data. However, it was not built with this in mind and I can already foresee issues potentially needing the 2nd core and much complexity. But if I can make it work, I would also be closely looking at shutdown code and would try and make it reliably shutdown if on power save mode or skip shutdown if in accuracy mode. I've not yet looked at that perspective, so you could well be right on the need for a delay.

Either way, if your network adjustments mean I can run the USB through the battery connector, it will remove a lot of heat issues that the USB power circuitry caused and was going to require potentially complex offsets for.

It might be worth raising a pull request to manage testing on, I'd be happy to also test tweaks.

@ahodsdon
Copy link

ahodsdon commented Jul 7, 2023

Thanks @mrexodia for documenting your explorations (and thanks @sjefferson99 for spinning up a branch with the modifications)! It's been a few months... have the fixes continued to hold? Any more hangs?

@mrexodia
Copy link
Author

mrexodia commented Jul 8, 2023

For the most part my changes are stable. The only “issue” is that the wifi connection seems unstable and I get a red LED pretty frequently. The reupload functionality kinda works though so it’s not a big deal, just delays the data by a few minutes.

From my analysis it usually fails resolving the domain and I have a myname.lan so it could be related to that.

@sjefferson99
Copy link
Contributor

@ahodsdon It has been running solidly since the patch, I had to go in the box to update my wifi password and had to clear cobwebs, which was novel.

I do often (anecdotally measured out the window at night) get red light disconnects, but these always resolve on a retry or two and only delay the data as mrexodia comments above. I have my mesh node about 10 metres away indoors behind a window as the station is at the bottom of my garden. That and given the nature of the Pico W antenna the connection is not amazing, I have blamed it on connection strength as I get far fewer disconnects when it's on my dev bench next to the AP. I note that it's not easy (or legal for FCC compliance purposes) to add a better antenna, perhaps a LoRaWAN solution might be worth exploring?

I have also noticed that while the heating of the BME280 is not as bad as on USB, it does still seem to be a bit off, so I might add some simple offset logic and see if that's good enough or needs a more complex equation.

@mrexodia
Copy link
Author

mrexodia commented Sep 8, 2023

Just wanted to update on my journey with the enviro. After the firmware modifications it has been continuously plugged in for ~4 months and it's chugging along just fine (didn't have to touch it except when I accidentally changed my wifi password).

The only issue I had was that I wasn't sure if the sensor values were correct. There are some questions around the temperature on USB power and the PM values seem to get quite extreme sometimes. Initially my plan was to build my own hardware to validate this, but nobody has time for this so I purchased an Atmotube Pro instead 😅

I simply put the devices next to each other and took the latest measurements at the same time. Here are the results:

Atmotube Pro Enviro Urban
Pressure (hPa) 1009.1 1008.4
Temperature (˚C) 25.0 25.6
Humidity (%) 44 48.3
PM1 (µg/m³) 14 28
PM2.5 (µg/m³) 17 41
PM10 (µg/m³) 19 44

The devices definitely don't seem to agree with each other, but the main concern is the temperature which seems substantially higher (thereby also affecting the humidity calculation). Additionally the PM values are way off and I would need to read the chip's datasheet again because this doesn't seem right. I live in an area known for bad air, so perhaps the Atmotube is just optimistic but the difference is between 'Good' air and 'Moderate' air which would be concerning for my bedroom...

I will leave both devices running for a few weeks and think about follow-up experiments to run. Hopefully I will get an API for the Atmotube too so I can create another Grafana dashboard like this:

image

As you can see the PM measurements are extremely jittery, which is why I was suspicious of them in the first place...

@sjefferson99
Copy link
Contributor

@mrexodia I connected an unmodified BME688 via the qw/st connector on my enviro weather to try and do something similar and found that board was even further form the average local temperature, so I suspect there is some recommended calibration you are expected to do with these devices that will need adding to the Enviro firmware. Let me know if you come across anything like that.

I am also considering adding a PM sensor to the weather using the qw/st connector, will advise if I see anything useful should I get to that. I know the PM sensors need to spin up the fan and stabilise, so I'm not sure if Enviro does this as I'm only familiar with my own board code, but I'll take a look at the enviro when I do get to this improvement on the weather.

@mrexodia
Copy link
Author

Yeah, normally the enviro doesn’t spin up the fans for long enough. I modified the firmware to be in spec though and it spins them for a full minute before taking a reading…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants