---------------------------------------- PicoGopher Part 6: here comes the sun December 04, 2022 ---------------------------------------- Written on my laptop, at a desk under a pile of electronic junk ---------------------------------------- Welcome to Part 6 of the PicoGopher journey! If you want to see how everything started, you can find the previous parts in my phlog at gopher://gopher.club/1/users/mala/ (also mirrored at gopher://gopher.3564020356.org). You can find the project's code at https://github.com/aittalam/PicoGopher (commit 39b2777). In the previous parts I showed how to develop PicoGopher from scratch, serve a gopherhole via Gopher and HTTP, redirect user connections to its IP via a captive portal, and power it with different kind of batteries depending on the use you want to make of it and its estimated consumption. Today we are going to power PicoGopher with solar. One of the main reasons I decided to jump in this field, which is new and completely unexplored for me, is that I'd like to think about PicoGopher as a sustainable way for people to build their own "geolocalized servers". These servers would also need to be as cheap as possible, as the plan would be to leave them more or less hidden somewhere, and generally unattended, potentially for long periods of time... I guess "not having your server stolen" is a reasonable extra problem to consider, but I will leave it as an exercise to the readers :-) Ultimately, I would like not just to prove this thing is possible in theory, but also have some back-of-the-envelope calculations to quantify how likely it is to work, how stable it will be, and so on. The good news is that there's quite some interesting material around and my work can rely on the experiments of many other people who attempted something similar. Just to name a few, the incredible Low-tech Magazine has a version of its website which is running on solar, and they documented both its creation [1] and its power analysis [2]. I particularly like how they show, in each page of the website, the battery level of the server, so everyone can estimate for how long it will be available before some sunlight is needed again. Another very interesting project is the one by Krzysztof Jankowski [3], who built a Gemini capsule on a solar-powered ESP8266 [4] (which made me want to either build a Gemini server for PicoGopher or a Gopher server on the ESP8266! ;-)). Last but not least, [5] shows how to build a solar-powered weather station and it has been my reference (as well as Krzysztof's, looking at the solution he implemented) for a solar prototype. ==== Steps to build PicoGopher ==== Below you can see the current status of the project. The steps marked as "x" have been completed, while those marked as "+" are described in this post. - [x] connect to the WiFi - [x] run a simple HTTP server - [x] run a mockup Gopher server - [x] load/save files - [x] make the Gopher server not a mockup anymore: - [x] translate gophermaps following gopher protocol - [x] load any file from disk - [x] set up the pico as an access point for geolocalised access - [x] make the server a bit more accessible - [x] enable async - [x] enable HTTP - [x] captive portal with PicoDNS - [x] powering PicoGopher - [x] better understand power consumption - [x] playing with batteries - [+] playing with solar - [+] monitoring power - [+] better understand power saving As you will see in the following, powering our project with solar is not a tremendously complicated task per se. However, as it involves a bit more electronics than I am comfortable with and depends on external factors such as having enough sunlight, I felt the need to add a few thoughts on monitoring power (so you can understad what is happening in realtime) and power saving (so you can deal with moments when there is just not enough sun to keep PG running). ======== Playing with solar ======= Solar power for DIY projects now seems to come as a turnkey solution from many online electronics stores. Being a total newbie in this field, I first looked on Pimoroni for a ready-to-use circuit and ended up buying Adafruit Universal USB/DC/Solar Lithium Ion/Polymer charger [6]. For a little less than 15GBP, this provides a hassle-free solution that you just need to connect to a 6V solar cell (e.g. [7]), a 3.7~4.2V battery (e.g. [8]), and of course the RasPi Pico. This approach significantly reduces the amount of things one has to solder (provided all the components have the proper plugs, i.e. 2-pin JST to connect battery+Pico and 5.5x2.1mm DC plug for power) but of course you pay for your peace of mind: the total cost for all the components is ~32 GBP, of which just 6 are for the Pico itself. Looking for a cheaper alternative, I also built an equivalent of what is presented in [4,5]: this makes use of a TP4056 [9] and a Schottky diod [10] for a cost of about 2 GBP, bringing the grand total below 20 Pounds. The only problem I found is that the solution is controversial to say the least. [11] warns that the TP4056 should not be used both as a charger and as a load driver at the same time, because when a load is present the charger might not detect charge completion so it might overcharge. Comments on [5] suggest to directly use a solar power management module like Waveshare's [12], which I have not tried but might be a good solution for our task at a smaller price than Adafruit's. Finally many, many tutorials on YouTube show a load which is directly connected to the same TP4056 outputs used for the battery. Long story short, I realised that the more I delved deeper into this rabbit hole the more I was getting inconsistent information, so I decided to try and solve a different problem. If I want to compare different approaches, how can I *measure* how battery charging/discharging is going? ========= Monitoring power ======== Being able to monitor incoming power has many advantages. First of all, you can measure empirically whether the time estimates we made in the previous post were realistic, i.e. how much time PicoGopher will leave with a given set of batteries. Then you can estimate battery health by looking at their charge/discharge curves [13,14] (and perhaps also get some insight into whether they are being overcharged). Last but not least, you can take decisions about what to do with your system depending on your battery charge level: for instance you can put it in standby mode, send a warning message to your readers, etc. For all this reason, I looked into how to make battery info available to the Pico and found that it is possible to use one of its analog pins (ADC0, ADC1 or ADC2, respectively available as GP26, GP27, and GP28 - see pinout in [15]) to read a voltage input. The value which is read from an ADC pin is an unsigned 16-bits int, so it will range between 0 and 65535 to represent voltages in the 0~3.3 Volts interval. Note, however, that while the maximum input voltage is 3.3V the Pico can be powered with voltages up to 5.5V. For this reason, we must find a way to reduce the input voltage to an ADC pin to a value which will not damage the Pico. The solution is using a voltage divider [16], which is nothing more than two resistors connected in series, with the input voltage (the one we are powering the Pico with) applied across the resistors pair and the output voltage (the one we are sending to the ADC pin) emerging from the connection between the two of them: Vin ---+ | R1 | +---- Vout | R2 | GND ---+ The relationship between the input voltage Vin and the output voltage Vout is: Vout = Vin * R2 / (R1+R2) This means that: - if R1 and R2 have the same resistance, then Vout = 1/2 Vin - if R1 = 2*R2, then Vout = 1/3 Vin - provided we know the relationship between R1 and R2, their value does not matter for the sake of calculating Vout. It is important though to control the current consumption, so it is best to use relatively large resistance values (e.g. 100K Ohm) to avoid wasting too much current for the measurement. The schematics and a few examples of connections with the Pico are available in [17,18]. For PicoGopher I chose two identical 100KOhm resistors and ADC3 (GP28) for tracking the battery charge values, so I had to multiply by 2 all the voltage readings and my conversion factor becomes conversion_factor = 2 * 3.3 / 65535 Note that this will change depending on which resistors you use in the voltage divider. Just to give you an example, the Pimoroni Pico Lipo Shim seems to have R1 = 2*R2 because they multiply the voltage read by 3 [19]. Their code also provides an estimate on the battery percentage left which is quite convienient: I blatantly copied into my code, adapting it for my Li-Ion batteries' voltage. Once I could read the voltage properly, I decided to track it in two different ways: the first one was by logging it into a `gopher/picopower.log` file; the second was by showing it live on an e-ink display (Pimoroni's Pico inky). The code for both is available on GitHub. The display allowed me to check the battery level at any given time, and from its latest update before the Pico turned off I could confirm that I can easily run PicoGopher for more than 12 hours on a fully charged 3.7V 1200mAh Li-Ion battery. This was a bit less than my initial estimation but I think it was reasonable, especially considering the fact that I added some extra machinery including the voltage divider, the TP4056 and the display. With the logs I was able to plot a discharge profile showing me the impact of solar cells during the day. This was particularly useful as it made me realise that London's sun in December is definitely not enough for a 1W solar cell to recharge my battery! Looking for a way to measure which kind of cells I would need for my task, I found [20] which allowed me to make a first estimate which I am trying to improve now (see [21] or, long story short, I will need at least 4W for a decent performance here). ========== Power saving =========== The Rp2040 datasheet [22] shows that the Pico can be put into different power saving states: SLEEP and DORMANT. It also provides C "hello_sleep" and "hello_dormant" examples showing how to do it. [23] shows how to do it in micropython instead, using light or deep sleep and consuming as low as 1.4mA during sleep. The story behind this though is quite interesting and it includes various experiments and patches [24,25] that were applied to micropython before the function was officially built into it. If you are still alive after this huge amount of references, I'd suggest you to take a look at it :-) I personally have not implemented power saving mode into PicoGopher yet, but my plan is quite simple: after voltage reading, if the value is below some threshold I will just put PG to sleep for a while. Ideally I would like to use the battery's voltage itself as a trigger to wake the Pico up, but I think I will settle for a fixed amount of time first. You will likely see this first implementation in the next update to picopower.py! =========== Conclusions =========== In this post I tried to summarize my attempt at making a solar-powered version of PicoGopher. Solar is a super interesting subject which was completely new to me and a rabbit hole which was definitely worth falling into. I think I am still quite far from the ideal solution I had in mind -mainly because the requirement for a bigger solar panel makes it a bit harder to leave PicoGopher wherever you like- but at the same time I am quite excited to know it is not just possible, but also way easier to implement in warmer and sunnier places. My soldering skills have definitely improved in the process and I have documented everything with photos, which I will share somewhere (I guess on my fosstodon account) and link here soon. This said, I think there are plenty of ways I could still improve this side of the project, and I would be very happy to hear feedbacks (and suggestions!) from you all. Feel free to reach out to me on Mastodon or via email, and many thanks to those of you who have already done it! ============ References =========== [1] https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website.html [2] https://solar.lowtechmagazine.com/2020/01/how-sustainable-is-a-solar-powered-website.html [3] https://krzysztofjankowski.com/ [4] gemini://gemini.p1x.in:1966/ [5] https://picockpit.com/raspberry-pi/raspberry-pi-pico-w-remote-weather-station-solar-powered-and-softap/ [6] https://www.adafruit.com/product/4755 [7] https://www.amazon.co.uk/gp/product/B0BDX551VC [8] https://shop.pimoroni.com/products/lipo-battery-pack?variant=20429082183 [9] https://www.amazon.co.uk/gp/product/B07BSVS842 [10] https://www.amazon.co.uk/gp/product/B087C7QRXF [11] https://www.best-microcontroller-projects.com/tp4056.html [12] https://www.waveshare.com/solar-power-manager.htm [13] https://learn.adafruit.com/li-ion-and-lipoly-batteries [14] https://batteryuniversity.com/article/bu-501a-discharge-characteristics-of-li-ion [15] https://datasheets.raspberrypi.com/picow/pico-w-datasheet.pdf [16] https://en.wikipedia.org/wiki/Voltage_divider [17] http://raspi.tv/2013/controlled-shutdown-duration-test-of-pi-model-a-with-2-cell-lipo [18] https://blog.rareschool.com/2022/08/how-can-you-make-your-picopico-w.html [19] https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/pico_lipo_shim/battery_pico.py [20] https://re.jrc.ec.europa.eu/pvg_tools/en/tools.html [21] https://fosstodon.org/@mala/109439846884942035 [22] https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf [23] https://ghubcoder.github.io/posts/pico-w-deep-sleep-with-micropython/ [24] https://ghubcoder.github.io/posts/deep-sleeping-the-pico-micropython/ [25] https://github.com/tomjorquera/pico-micropython-lowpower-workaround