Header Ads

Zoey the Zion

Solar Logger

Introduction

I like to leave the fridge on in Zoey so we can hit the road, whether for a trip to the beach or a quick get away.    We have a lot of mature Oak trees in the area and I have found if I park underneath the trees that over a couple days the solar can't keep up with the fridge.   

Then, despite warning myself many times, I left the invertor on and went out to Zoey two days later to find the low battery alarm going off....

So time for a battery alert...

*** Warning - Technical Mumbo Jumbo follows :) ***

Solar Controller

The Zion has an EPEPVER solar controller.   A quick look at the manual shows that is has an RJ45 port on the back that has an RS485 signal and 5-7.5V DC.

RS485 uController

I am a fan of the ESP32 line of uC mostly because of the built-in Wifi and Bluetooth chips.   I went searching for a dev board that also had a RS485 chip and came across the LilyGo T-CAN485.

Wiring

I made a custom cable using some cat6 I had lying around.    I expect you could also cut the end off of an ethernet cable.  The pinout on the Epever (in the manual) has 2 pins for each signal.    I used one of the grounds for power and one of the grounds connected to the RS485 input.  This is to ensure no grounding issues when powered off of USB for testing/programing.

Software

A wrote the firmware in Arduino studio leveraging the modbus library.   Logic summary:

  • Scan for available SSIDs
  • If my home or starlink wifi is available, connect to the wifi.
  • Enable the RS485 controller
  • Query 20 registers from the solar controller using the modbus protocol
  • Post the data to a google spreadsheet via an HTTPS post through a Google form (super lightweight on the uC side compared to using the sheets API)
  • Set a 15 minute deep-sleep timer on the Real-time clock 
  • Go to deep-sleep mode (turns off everything except the RTC clock)
  • 15 minutes later it powers back on and repeats.
Snippet:
uint16_t  getregister(int reg)
{
    //#include <ModbusMaster.h> - Global
    //ModbusMaster node; - Global

    if (node.readInputRegisters(reg, 1) == node.ku8MBSuccess)
    {
      //*most* registers just need a "/ 100.0"
      //status registers need a bit mask.  Values are multiplied by 100 so later on we can simply /100
      //we don't /100 now because passing and printing ints are better then floats in Arduino libraries

     switch (reg)
     {
      case CE_STATUS_:
        return ((node.getResponseBuffer(0) & 0x000C) >> 2) * 100;  // mask bits 3 and for and move to the right
        break;
      case BT_STATUS_:
        return (node.getResponseBuffer(0) & 0x000F); // * 100;
        break;
      case DE_STATUS_:
        return (node.getResponseBuffer(0) & 0x0002) * 100;
        break;
      default:
        return node.getResponseBuffer(0);
     } //switch
    }
    else
    {
      Serial.print("error getting register: ");
      Serial.println(reg);
      return 0; //no valid data
    }
}

Dashboard

I have done a few projects previously using a Google sheet to store data and a Looker datastudio report to display the data.   I do like free tools.

I created a report that shows the last reported data plus a historical view of the Solar and Battery voltages.    For anyone trying to duplicate, the trick for showing "last received" data in a time-series data set is to create a blend with the same data set on either side of a left hand join.   Add a calculated field that is the MAX() of your date field and join that with the date field on the other side of the join.



Alerting

One reason I like using Google sheets for this type of data storage is you can write App Script functions that can be triggers based on time or when data is posted to the spreadsheet.

I created an appscript function that triggers on a form post to the spreadsheet and acts on the battery voltage.
  • Write the voltage to a persistent script property - this allows you to access the results from other functions in the same script.
  • Check if the voltage is < 13.0
  • Call the prowlapp.com API to send an alert to my mobile phone.    (This could have been an email, but I wanted the mobile alert)

function onFormSubmit(e) {
 

  const timestamp = e.namedValues['Timestamp'];
  const batteryV = e.namedValues['BT_VOLTAGE'];

  if(!batteryV)
  {
    console.log("No battery voltage returned.");
    return;
  }
  console.log("Battery from form:"+batteryV);
     
  // Store the entry ID in user properties
  const scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.setProperty('batteryV', batteryV.toString());
  scriptProperties.setProperty('timestamp', timestamp.toString());

  lowbattery(batteryV, timestamp);      
 
}


I also added some logic to suppress duplicate alerts as well as send a notification every day at noon with the last recorded voltage.

Future

  • 3d print a case
  • Tweak the sleep cycle after I collect some data.    Pushing to 30 or 60 min deep sleep cycle will even further reduce the power draw from the monitoring circuit.
  • Clean up the code and post on github
  • Add functionality to the software so you can optionally put the hardware in pass-thru mode so you can use the Epever software to control the controller directly.
    • In debugging I had a test firmware that just passed data back and forth between the USB and RS485 interface on the uC and was able to run the Epever software.
  • Add a BLE or ESP-NOW data burst on boot to support a remote display.
    • Maybe BLE so you can see it with a mobile phone using one of the BLE utilities on the app store



Powered by Blogger.