Showing posts with label Solar. Show all posts
Showing posts with label Solar. Show all posts

Saturday, 7 October 2017

Bluetooth IoT Solar Battery Voltmeter Redux

From the last post we showed that the 3.3V TTL Arduino HC-06 can be mounted to an RS-485 USB PIC18F14K50  and be made to work. Here we add the analog input feature from another earlier post and hopefully the HC-06 will play nice. That was indeed the case, after a little persuasion.

Arduino HC-06 with RS-485 USB PIC18F14K50
This removed the need to use a Raspberry Pi for our Solar Battery Voltmeter and save 160mA of current consumption.

Mounted on the solar battery. The power adapter is a USB phone charger for use in a car cigarette lighter socket
The php script on the webserver simply executes the bluetooth master code directly, and the bluetooth link proved workable despite the webserver being inside the study with the doors and windows closed at least 10m away.

Despite the apparently simple task of integrating two features, caution is recommended. I modified a new RS-485 USB dongle for bluetooth and re-tested every time something new is added. The original working set is kept in case I needed a good set to test my software. Otherwise hardware and software errors tend to feed each other and you end up with an indigestible tangle.

First the new build was tested using easyhooks exactly like the previous post. Take care not to change the software at this point.

Next the bluetooth cable was assembled and the whole lot was retested. The HC-06 defaults to 9600 baud but the USB PIC18F14K50 starts up at 19200 baud. It was trivial for the Raspberry Pi to set the latter to 9600 baud, but without the Pi the PIC18F14K50 had to be made to power up at 9600 baud.

The analog input mod was then added. Here was a new wrinkle - when the analog code transmitted over the bluetooth channel somehow the result bytes fed back into the bluetooth receiver and triggered yet more transmissions. The PIC18F14K50 program was modified to only start analog input (and transmitting) only on receipt of the command 'z' and not just any keystroke.

The software is much the same as the last bluetooth post:

root@aspireE1:/home/heong$hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: A4:DB:30:55:9C:AA  ACL MTU: 1022:8  SCO MTU: 183:5
        DOWN
        RX bytes:574 acl:0 sco:0 events:30 errors:0
        TX bytes:368 acl:0 sco:0 commands:30 errors:0

If you get nothing at this stage, you do not have a bluetooth controller, but if you get output like that above you go on to:

root@aspireE1:/home/heong$hciconfig hci up

If you check again your controller should read 'UP':

root@aspireE1:/home/heong$hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: A4:DB:30:55:9C:AA  ACL MTU: 1022:8  SCO MTU: 183:5
        UP RUNNING
        RX bytes:1148 acl:0 sco:0 events:60 errors:0
        TX bytes:736 acl:0 sco:0 commands:60 errors:0

root@aspireF15:/home/heong$bluetoothctl
[NEW] Controller 00:15:83:15:A3:03 BlueZ 5.40 [default]
[NEW] Controller C8:FF:28:27:7D:2C BlueZ 5.40
[bluetooth]# devices
[bluetooth]# paired-devices
[bluetooth]# power on
[CHG] Controller 00:15:83:15:A3:03 Class: 0x00010c
Changing power on succeeded
[CHG] Controller 00:15:83:15:A3:03 Powered: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:15:83:15:A3:03 Discovering: yes
[NEW] Device 98:D3:32:20:BB:7B 98-D3-32-20-BB-7B
[CHG] Device 98:D3:32:20:BB:7B LegacyPairing: no
[CHG] Device 98:D3:32:20:BB:7B RSSI: 127
[CHG] Device 98:D3:32:20:BB:7B Name: HC-06
[CHG] Device 98:D3:32:20:BB:7B Alias: HC-06
[CHG] Device 98:D3:32:20:BB:7B LegacyPairing: yes
[CHG] Device 98:D3:32:20:BB:7B RSSI is nil
[bluetooth]# agent
Missing on/off/capability argument
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful
[bluetooth]# pair 98:D3:32:20:BB:7B
Attempting to pair with 98:D3:32:20:BB:7B
[CHG] Device 98:D3:32:20:BB:7B Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 98:D3:32:20:BB:7B UUIDs: 00001101-0000-1000-8000-00805f9b34fb
[CHG] Device 98:D3:32:20:BB:7B Paired: yes
Pairing successful
[CHG] Device 98:D3:32:20:BB:7B Connected: no
[CHG] Device 98:D3:32:20:BB:7B Connected: yes

At which point we do:
root@aspireF15:/home/heong/mpg$rfcomm bind /dev/rfcomm0 98:D3:32:20:BB:7B 1

The python script (easily called by a webhost PHP script) is:
root@aspireF15:/home/heong/solar$cat analog_pic/bluetooth_solarbat.py
#!/usr/bin/python
import serial
from time import localtime, strftime, sleep

port=serial.Serial('/dev/rfcomm0', timeout=3)

if __name__ == "__main__":

  sleep(5)
  Vbat = ''
  port.write('z')
  Vbat= port.read(100)
  Battery_Voltage=int(format(ord(Vbat[0]), '02x'), 16)*256 + \
                  int(format(ord(Vbat[1]), '02x'), 16)
  if Vbat[2:5] != 'HCM':
    print 'HCM Checkbyte Fail', Vbat

# Calibrated_Battery_Voltage = Battery_Voltage * 13.75 / 689
  Calibrated_Battery_Voltage = (Battery_Voltage * 5.0) / 1024 # convert to floating point
  print 'Bluetooth power',
  print format(ord(Vbat[0]), '02x'),
  print format(ord(Vbat[1]), '02x')


  print Calibrated_Battery_Voltage,'Volts',strftime("%Y-%m-%d %H:%M:%S", localtime())

  Battery_Voltage=int(format(ord(Vbat[5]), '02x'), 16)*256 + \
                  int(format(ord(Vbat[6]), '02x'), 16)
  if Vbat[7:10] != 'LJP':
    print 'LJP Checkbyte Fail', Vbat

  for j in range(len(Vbat)):
    print format(ord(Vbat[j]), '02x'),
  print('\n')

# Calibrated_Battery_Voltage = Battery_Voltage * 12.56 / 640
  Calibrated_Battery_Voltage = Battery_Voltage * 13.75 / 689
  print 'Solar battery power',
  print format(ord(Vbat[5]), '02x'),
  print format(ord(Vbat[6]), '02x')
  print Calibrated_Battery_Voltage,'Volts',strftime("%Y-%m-%d %H:%M:%S", localtime())


Note the raw output is still printed at this stage to aid with calibration.
One of the analog inputs have been connected to the PIC18F14K50 input power (5V), as it might come in handy should I connect the setup directly to the solar panel output, bypassing the battery.

When executed the script should read:

root@aspireF15:/home/heong/solar$analog_pic/bluetooth_solarbat.py
Bluetooth power 03 f9
4.9658203125 Volts 2017-10-08 08:40:05
03 f9 48 43 4d 02 7f 4c 4a 50

Solar battery power 02 7f
12.7521770682 Volts 2017-10-08 08:40:05

There you have it, a solar battery voltmeter that only takes 30mA at 5V. A wireless IoT device makes a voltmeter lot safer to read, and gives us the confidence to later connect it to read much higher voltages- 100Vac, 240Vac, 340Vdc. Imagine dropping one of these babies into a 10KW inverter (used electric vehicles, escalator, elevator) to diagnose problems. Makes a change from poking at the charred remains trying to do the same.

I originally intended to post a link to the PHP script to read the battery voltage online, but for some reason bluetoothctrl would not run properly on my Beaglebone White webhost CPU nor my backup webhost, an older Acer laptop.

Which brings me to why I like using a full Linux installation as an embedded controller whenever I can. When prototyping, little niggles like this crop up all the time. With a full installation, this almost never become a show-stopper. This is because it is much easier to modify a full Linux installation than any system which has already been cut down, like busybox, uLinux or a dedicated embedded OS.

Happy trails. 

Monday, 25 September 2017

Bluetooth IoT Solar Battery Voltmeter

A man is like Bluetooth , he's connected to you when you're nearby, but search for others when you're far away.

A woman is like Wi-Fi , she notices all the available ones but connect to the strongest.
But remember, Bluetooth will stick close to you because it's made that way.


The Arduino HC-06 is an amazingly inexpensive Bluetooth module. It may actually be better to buy the HC-05 as it can be set to master or slave. The HC-06 commonly comes in slave configuration (technically the HC-06-S. The master is HC-06-M). It is serial port(UART) to Bluetooth adapter. I bought the HC-06 slave because it has fewer settings to worry about. The master will be my laptop bluetooth module.



Rather inconveniently its TTL level is 3.3V, while my USB RS-485 adapter is 5V TTL. I could have swapped in a 3.3V PIC18LF14K50 for a perfect fit, but it meant junking a perfectly good 5V PIC18F14K50. It is simple enough to use a resistor divider:
  
Notice that the resistive divider is only necessary for the PIC18F14K50's TX pin. A 5V TTL device will read a 3.3V signal from the HC-06 but the converse will damage the HC-06.

For test purposes I used an unmodified USB to RS485 board. I removed the RS-485 IC, the MAX485E so that it would not interfere with the HC-06. The latter is powered from the 5V line of my USB hub. Connect up 2 lines for 5V and 0V, RX of HC-06 to TX of the PIC18G14K50, and TX of HC-06 to RX of PIC18F14K50 and plug right in:
CH340G USB To TTL Converter

You can buy a USB to TTL serial dongle online for RM12.88.the CH340G USB to TTL adapter . It even has a selector for 5V/3V operation so you don't have to mess about with resistor dividers. 

USB RS485 dongle with Bluetooth HC-06 module. Notice the current is still 10mA.
With Bluetooth active it is 20mA
When powered on successfully, the HC-06 blinks red.

Next we whip out our laptop running Linux (I use Slackware) and invoke hciconfig:
root@aspireE1:/home/heong$hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: A4:DB:30:55:9C:AA  ACL MTU: 1022:8  SCO MTU: 183:5
        DOWN
        RX bytes:574 acl:0 sco:0 events:30 errors:0
        TX bytes:368 acl:0 sco:0 commands:30 errors:0

If you get nothing at this stage, you do not have a bluetooth controller, but if you get output like that above you go on to:

root@aspireE1:/home/heong$hciconfig hci up

If you check again your controller should read 'UP':

root@aspireE1:/home/heong$hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: A4:DB:30:55:9C:AA  ACL MTU: 1022:8  SCO MTU: 183:5
        UP RUNNING
        RX bytes:1148 acl:0 sco:0 events:60 errors:0
        TX bytes:736 acl:0 sco:0 commands:60 errors:0

Next we use bluetoothctl:

root@aspireF15:/home/heong$bluetoothctl
[NEW] Controller C8:FF:28:27:7D:2C BlueZ 5.40 [default]
[NEW] Device 98:D3:32:30:BE:15 HC-06

If you do not see the last line with HC-06, it just means it is your bluetooth module has not been turned on. If your computer does not have bluetooth, a USB bluetooth dongle is very cheap. To turn on your bluetooth, simply do (while still in bluetoothctl). 

Note that some laptops may require to press a button or a keyboard combination (Acer used to have Fn-F3).

[bluetooth]# power on
[CHG] Controller C8:FF:28:27:7D:2C Class: 0x00010c
Changing power on succeeded
[CHG] Controller C8:FF:28:27:7D:2C Powered: yes

If it still does not come up then do:

bluetooth]# scan on
Discovery started
[CHG] Controller C8:FF:28:27:7D:2C Discovering: yes
[CHG] Device 98:D3:32:30:BE:15 LegacyPairing: yes

Next you launch an agent to handle the authentication:

[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful

Next you pair your laptop bluetooth module with the HC-06:

[bluetooth]# pair 98:D3:32:30:BE:15
Attempting to pair with 98:D3:32:30:BE:15
[CHG] Device 98:D3:32:30:BE:15 Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 98:D3:32:30:BE:15 UUIDs: 00001101-0000-1000-8000-00805f9b34fb
[CHG] Device 98:D3:32:30:BE:15 Paired: yes
Pairing successful

If the pairing has been successful, the HC-06 blinkenlight will be just on, and no longer blinking.

Next I used rfcomm to create a device file /dev/rfcomm0:

rfcomm bind /dev/rfcomm0 98:D3:32:20:BB:7B 1

At this point you are ready for the final test. You need minicom, a serial terminal emulator. Launch 2 instances on 2 consoles (I use KDE's konsole). Aim one minicom at the bluetooth device /dev/rfcomm0 and the other at /dev/ttyUSB0 (usually, but your usage may vary depending on your USB serial dongle). Set the baurate in both minicom to 9600 baud, 8 bits, 1 stop, no parity. Flow control is None.

Type into each minicom console and watch the results appear in the other. Repeat for each console as you need to check both TX and RX.

And there you have it, an HC-06 sending (and receiving) data. In the next post we shall connect the HC-06 to the IoT Solar Battery Voltmeter, so stay tuned.


Solar Battery Blues

The IoT Solar Battery Voltmeter project resulted in a dead battery. It now does not accept a charge, and its voltage dropped below 12V very quickly when discharging, indeed when it was not being charged. There is nothing else to do but to replace it.
20 minutes after sundown the battery voltage went from 14V to 10.9V

Now before I get too misleading, it is not a good idea to use a car battery in place of a deep-cycle battery. I started experimenting doing just that around 12 years ago mainly because they cost about half of the deep cycle ones.

3KW sine-wave UPS APC Matrix 3000 hacked to accept 4 36Ah Yuasa 50B24R

The idea was to over-rate the car batteries and hopefully they will then have a worthwhile lifetime and cost. The reason for this is all cars have a residual load on the battery when not in use. This comes from the digital clock, stereo, alarm and the various car engine electronic modules. It is thought the load here should be 85mA for a new model and 50mA for an old model.

So in general you cannot replace a deep-cycle battery with a car battery, unless the load is less than 100mA.

After all these years progress have overtaken the lead acid car battery. I recently bought a 20Ah (at 3.7V) lithium-ion power bank for RM87. This is somewhat comparable to my 36Ah (but at a stonking 12V)  Yuasa at RM195. Now lithium-ion batteries are deep-cycle so they are definitely worth investigating.

This lithium-ion power bank is rated 20Ah25V and costs RM87
After all this is why I built the IoT Solar Battery monitor, to investigate batteries and their chargers.

So, apart from obvious misuse, exactly what went wrong? The load was only 200mA, and Yuasa 50B24R ECO-R GS car battery, it should be more than enough. 50B24R is nominally 36 Ampere-hours. If it completely discharged (again, not a good thing) it could output 3A over the 12 hours of a tropical night.

The actual current draw was 0.2A at 5V. This should translate to 0.083A at 12V. Assuming the 12V to 5V conversion efficiency of 75%, we can downrate it to 0.111A at 12V. At 111mA the battery should last 324 hours or 13 days. So the battery is way over-sized and yet lasted only nine months much less than the expected 3 years lifetime I get from the same battery in my car.

The problem could also be in previous tests on the solar battery I had completely discharged it 3 or 4 times. Now car batteries do not like to be over-discharged and they will fail prematurely. So, the 36Ah Yuasa 50B24R was right there at the edge, and the previous deep discharges may have tipped it over.

A simpler cause can be that the solar panel's charging rate could not keep up with the discharge rate at night, and over a few days the battery progressively got weaker and eventually completely discharged. The solar panel will put out a variable charge depending on the weather and we have had unseasonably rainy weather recently. Indeed the reason to build the IoT Solar Battery Voltmeter was to investigate this.

It could also be that my Gamma solar charge controller was optimized for deep-cycle batteries and somehow it damaged the car battery by overcharging. One clue is that the battery charging voltage is often 14 to 14.8V, clearly over the 13.8V trickle charge limit for a fully-charged battery.

In any case, the IoT Voltmeter consumed too much of the battery charge it was monitoring (this left only 30mA for the load!), and we could do with a leaner voltmeter.

Of course we could power the voltmeter separately using another battery, or even from mains power. Mains power would have been ideal, except we live on top of a little hill that seems to get struck by lightning a lot, and to get the weeks-long data we need, an isolated system like a battery-powered voltmeter seems like a good idea.

Alternatively we can try using inductively-coupled wireless charging like the Qi, often used to charge smartphones.

The Qi wireless charger & receiver combination can deliver some 500mA at 5V, enough to power the Raspberry Pi-based IoT Voltmeter


Indeed we will try both ideas, but it seems wise to try to reduce the power consumption of the Voltmeter. This brings us to the PIC18F14K50-based voltmeter minus the Raspberry Pi. The PIC18F14K50 USB RS485 board I used consumed only 10mA at 5V. This should give me a maximum load of 90mA for a N60 car battery.

The PIC18F14K50 converted to transmit its data via RS-485 takes only 10mA..

Now I can get it to transmit data back using its RS-485 port, indeed I have already done so, but RS-485 involved copper wiring back to my webserver and this broke the mains isolation.

To maintain isolation I need a wireless data transmission method, and it seems like a good idea to try Bluetooth. There is an existing product for sale that will do exactly that, but the price is a little high:

The CTEX CTX bluetooth battery monitor costs RM305

The Arduino HC-06-S bluetooth slave is only RM15

 Besides, rolling your own is not only cheap, but might be fun. Happy trails.

Tuesday, 12 September 2017

Internet of Things: Solar Battery Voltmeter

Get solar battery voltage now

From the last post, we have a car battery being charged by a solar panel, and to monitor the battery voltage we have a Raspberry Pi with a WiPi (USB WiFi dongle for the Pi) with an added USB serial port dongle hacked as a voltmeter.

Solar panel charging a car battery


Quick, basic way to present information in the Internet of Things


Now I can log into my Pi remotely through wifi:

ssh -t 172.16.1.10

A python program can be written very quickly, say solarbat.py:
#!/usr/bin/python
import serial
from time import localtime, strftime

port=serial.Serial('/dev/ttyACM0', timeout=1)

if __name__ == "__main__":

  port.write('A')
  Vbat= port.read(10)
  Battery_Voltage=int(format(ord(Vbat[0]), '02x'), 16)*256 + \
                  int(format(ord(Vbat[1]), '02x'), 16)
  if Vbat[2:5] != 'HCM':
    print 'Checkbyte Fail' 

# Calibrated_Battery_Voltage = Battery_Voltage * 12.56 / 640
  Calibrated_Battery_Voltage = Battery_Voltage * 13.75 / 689

  print Calibrated_Battery_Voltage,'Volts',strftime("%Y-%m-%d %H:%M:%S", localtime())


When executed:
root@piface1:/home/heong/analog_pic# ./solarbat.py
12.893625 Volts 2017-09-06 13:48:55

Technically speaking it is an Internet of Things device now. I have set up my modem router to host my website www.cmheong.com, and if you logged into my webhost, you could now remotely trigger the battery voltage measurement and retrieve the result:

$ ssh -t root@172.16.1.10 /home/heong/analog_pic/solarbat.py
root@172.16.1.10's password:
12.91325 Volts 2017-09-06 13:52:24
Connection to 172.16.1.10 closed.

A bash script can be set up in the webserver to log in automatically, execute solarbat.py and retrieve the results. What bash can do, an Android smartphone can. 

And there you have it, a first cut of an IoT Solar Battery meter.
It is more common to expose this functionality via a network socket, and for this to happen we need two more programs, a server program to run solarbat.py on the Pi, and to forward the results to the webserver.

The webserver runs a client program using a PHP script. The script runs client program to extract and displays the results.

I got some sample code from here (honestly I have never done this before and all it took was a couple of hours). The client code is unmodified:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int main(int argc, char *argv[])
{
    int sockfd = 0, n = 0;
    char recvBuff[1024];
    struct sockaddr_in serv_addr; 

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000); 

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    } 

    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
    {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
        }
    } 

    if(n < 0)
    {
        printf("\n Read error \n");
    } 

    return 0;
}

The server code I modified to invoke solarbat.py when a client request triggers it:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int readfile(char *buffer, int maxsize)
{
  FILE *fileread = NULL;
  char *filename = "solarbat.txt";
  unsigned int i = 0;

  fileread = fopen(filename, "r");

  if(fileread == NULL)
  {
    int saved_errno=errno;
    if(saved_errno == ENOENT)
      printf("File %s does not exist\n", filename);
    else
      printf("errno is %d\n", saved_errno);
    buffer[0]=0;
    return 0;
  }
  else
  {
    // printf("%s successfully opened, reading file ...\n", filename);
    while(!feof(fileread)) // read only the last line
      i=fread(buffer, 1, maxsize, fileread);
    if (i<maxsize) // terminate string for printf
        buffer[i] = 0;
    else
        buffer[maxsize]=0;
    fclose(fileread);
    return i;
  }
}

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 

    char sendBuff[1025];
    char readBuff[1025]; // cmheong 2017-09-11

    time_t ticks; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    while(1)
    {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

        system("/home/heong/analog_pic/solarbat.py > ./solarbat.txt");
        readfile(readBuff, 1024);

        snprintf(sendBuff, sizeof(sendBuff), "%s", readBuff);
        write(connfd, sendBuff, strlen(sendBuff)); 

        close(connfd);
        sleep(1);
    }
}

To compile, you do (in Pi):
gcc -o solar_server solar_server.c

Over at your web server you do:
gcc -o client client.c

This seems a bit pedantic but it takes care of the different systems- the Pi is an ARM system and the webhost can be an Intel-based blade server.

To execute, you run on the Pi:
 ./solarbat_server

Over on client you do (assuming 172.16.1.10 is the address of the Pi):
 ./client 172.16.1.10
Mon Sep 11 14:15:45 2017

The last step is the php script. solarbat.php

<!DOCTYPE html>
<html>
<body>

<?php
echo "<h2>Solar Battery Voltage</h2>";
$last_line = system('/home/heong/socket/client 172.16.1.10', $retval);
//echo $last_line;
?> 

</body>
</html>

Now to get the solar battery measurement you only need to aim your browser at the script:

http://www.cmheong.com/solar/solarbat.php

Should get you this screenshot:


The Internet of Things is that simple. Happy Trails

Update Thu 14 Sep 2017: yesterday the weather was overcast a good part of the afternoon (the panel faced west) and the battery did not charge up properly. Over the night, the Raspberry Pi completely discharged the battery and only restarted the morning of the 14th when the sun came up. The php link stopped working - my apologies.

The voltmeter readings themselves told the story: