mala::notes

      ----------------------------------------
       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