Thursday, 5 May 2022

LS2024B Landstar PV charge controller LoRaWAN monitor

This has evolved over some months the latest device is based on a Heltec AB-02 CubeCell Dev Board Plus. (https://heltec.org/project/htcc-ab02/)




There is a  18650 3.6v (nominal) 2600mAh cell connected directly to this board and a RS-485 isolated interface board (Isolated TTL to RS485 3.3V 5V Converter Board Module Serial for Raspberry https://www.ebay.ie/itm/202608485280)  whose VCC (VDD) , TXD (TX2), RXD (RX2)and GND (GND next to VEXT) pins are connector to the AB-02 board as indicated in brackets (NOTE: GND pin next to VIN has a faulty connection).





The RJ-45 lead from the LS2024B provides A, B, GND and 7.5v


The 7.5v from the RJ45 (pin 1 blue/white) was dropped down to 6.66v using three signal diodes in series and then fed into the VS* :Solar input pin(5.5V~7V) on the AB-02.

The GND, A and B pins of the RS485 interface board were wired to pins 8 (brown), 6 (orange) and 4 (blue) respectively of the RJ45 cable (see drawing above)

To support access to the AB-02 debug output it'sTX1/RX1/GND were connected to a flying USB cable (without the +5v wire connected).


The sketch for the board is shown below:

#define SKETCH_NAME     "Cubecell_PV_esmart3_monitor_slan-032_v1.21"
#define VERSION         "Tues 3rd May 2022 21:24"

#define LOOP_DELAY_MSECS  1000 // 1 sec
#define MAX_TICKS         30 // 5 mins (very approx)

// https://www.thethingsnetwork.org/forum/t/cubecell-ab02-oled-power-off-for-deep-sleep/45008

/* Version history
 * 
 * v1.20   Fri  14th Jan 2022 11:34    Fixed lack of transmission and added display button (slan-032 variant)
 * v1.19 Thurs  13th Jan 2022 13:23    slan-032 version
 * v1.18 Thurs  13th Jan 2022 13:23    Abandoned leaky buckets not precise enough for straight averaging
 * v1.17 Weds   12th Jan 2022 22:47    Added 15/16 leaky bucket and continuous measurements
 * v1.16     Sun 9th Jan 2022 23:12    Created slan=032 CubeCell for final build and added display.stop()/connect() and comms. errs 
 * v1.15     Sun 9th Jan 2022 21:28    Added display support and tested with USB programming cable so no 5v
 * v1.14     Sun 9th Jan 2022 18:10    Added rx checksum checking as rx data was bad when powered from LS20124B
 * v1.13     Sun 9th Jan 2022 17:01    Now works by having RE/DE enabled all the time and discarded echoed 8 byte commands 
 * v1.12     Sun 9th Jan 2022 16:23    Changed back to using my Modbus tx/rx code but with RE and DE control 
 * v1.11     Sun 9th Jan 2022 15:30    Changed to using ModbusMaster library and steveiboy code
 * v1.10     Sun 9th Jan 2022 15:30    Changed to using MAX485 module 
 *  v1.9     Sun 9th Jan 2022 14:55    Changed sketch name to "Cubecell_PV_epever_monitor_slan-031_v1.9" 
 * 
 */
/*
    This code is for reading data from an EPEver LandStar B ( LS1024B )
    SOlar PV MPTT Charge controller is bassed on code posted to a
    forum topic:
    
    https://forum.arduino.cc/t/epsolar-solar-charge-controller-monitoring-system/895450/3
    
    by steveiboy. I have kept those he credited in this description :)
    
    However, my code is different in five ways:
    
    1) It used a Heltec CubeCell AB02 rather than an NodeMCU clone.
    
    2) It sends its data via LoRAWAN to The Things Network rather than via WiFi to an MQTT Broker.
    
    3) It uses an isolated RS485 interface board rather than a MAX485 board.
    
    4) It communicates in raw byte rather than us teh excellent ModbusMaster library
    5) It benefits from having a second serial port that it can use.
    Both modules are powered using the (in my case) 7.5 Volt supply-voltage
    that is available at the RJ45 port. If you're using another MCU make 
    sure, the onboard voltage-regulator can handle the 7.5 volts from the EPEver.
    
    To avoid the need of a level-shifter, the max485 module is powered only
    with 3V3 from the CubeCell, which works for me, but YMMV.
    
    Power-consumption is roughly XXX during Deep-Sleep, mostly due to the
    onboard leds, I guess. When running, the power-demand gets up to about
    YYY for 3-4 seconds.
    
    Connections:
    https://resource.heltec.cn/download/CubeCell/HTCC-AB02/HTCC-AB02_PinoutDiagram.pdf
            MAX485         NodeMCU   Heltec CubeCell Dev-Plus HTCC-AB02
            DI              TX              UART_TX2  TX2 (30)
            RO              RX              UART_RX1  RX1 (17) (NOTE: TX1 used to output debug!)
            VCC             3V3 !!!
            GND             GND

            So looking at the Epever with the COM port at the right labelled COM and the pins from
            left to right are?   1 2 3 4 5 6 7 8 
            
            
         EpEver RJ45                        MAX485      NodeMCU
        pin1  +7.5 V       org-wht                       Vin
        pin8  GND          brn                           GND
        pin6  RS-485-A     grn               A
        pin4  RS-485-B     blu               B
    connect DE (Max485) with a pull-down resistor (e.g. 6k7) to GND,
    to hold that line down in Deep-Sleep to lower power consumption
    connect D0 (NodeMCU) with reset (NodeMCU) for DeepSleep wake-up to work
    connect D6 (NodeMCU)and D7 (NodeMCU) to enable debug-mode. this
    sets the sleep duration to only 10 seconds
    some datasheets list different pinouts for the RJ45 jack!  swap A<->B if
    connection fails. Check voltage-level and -polarity before connecting!
    I'm excessively using the union-struct trick to map buffer-data
    to structs here. Most of the defines for the data-locations
    are for reference only and not actually used in the code
    I got loads of info for this from:
        https://www.eevblog.com/forum/projects/nodemcu-esp8266-rs485-epever-solar-monitor-diy/
        http://4-20ma.io/ModbusMaster
    For taking the data to grafana, have a look here:
        https://github.com/glitterkitty/mqtt-mysql
*/

#include "Arduino.h"
#include "LoRaWan_APP.h"
//#include <ModbusMaster.h>
// For a connection via I2C using the Arduino Wire include:
#include <Wire.h>               
#include "HT_SH1107Wire.h"
// Handy for seeing missing Modbus bytes
boolean   debug  = false;  // For RS-485 comms.
boolean   debug2 = false; // For LoRa comms.
boolean   info = false; // For status messages
//SH1107Wire  display(0x3c, 500000, SDA, SCL ,GEOMETRY_128_64,GPIO10); // addr, freq, sda, scl, resolution, rst
extern SH1107Wire  display; // Handled by "LoRaWan_APP.h"
// Pins
//
// ./CubeCell-Arduino/cores/asr650x/board/inc/board-config.h
// ./CubeCell-Arduino/cores/asr650x/board/inc/gpio.h
// ./CubeCell-Arduino/cores/asr650x/cores/ASR_Arduino.h
// ./CubeCell-Arduino/cores/asr6601/base/ASR_Arduino.h
// ./CubeCell-Arduino/variants/CubeCell-ModulePlus/pins_arduino.h
// 


#define MAX485_DE       GPIO2 // D2  // data or
#define MAX485_RE       GPIO1 // D1  //      recv enable
void preTransmission()
{
  digitalWrite(MAX485_RE, 0 /* 1 */); // Receiver Enable LOW to receive
  digitalWrite(MAX485_DE, 1); // Driver Enable HIGH to transmit
 // digitalWrite(LED, LOW);
}
void postTransmission()
{
  digitalWrite(MAX485_RE, 0); // Receiver Enable LOW to receive
  digitalWrite(MAX485_DE, 1 /*0*/);  // Driver Enable HIGH to transmit
  //digitalWrite(LED, HIGH);
}

/* OTAA para*/
//uint8_t devEui[] = { xxx.. };  // MSB (V3 slan-031)
//uint8_t appEui[] = { xxx.. };  // MSB
//uint8_t appKey[] = { xxx.. }; // MSB
uint8_t devEui[] = { yyy..};  // MSB (V3 slan-032)
uint8_t appEui[] = { yyy.. };  // MSB
uint8_t appKey[] = { yyy..}; // MSB
  
/* ABP para for xxxxxx */
uint8_t nwkSKey[1];
uint8_t appSKey[1];
uint32_t devAddr = 0; // <-- Change this address for every node!
uint32_t appTxDutyCycle = (5 * 60 * 1000); // the frequency of readings, in milliseconds (set to 5 mins)
uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 };
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
DeviceClass_t  loraWanClass = LORAWAN_CLASS;
bool overTheAirActivation = LORAWAN_NETMODE;
bool loraWanAdr = LORAWAN_ADR;
bool keepNet = LORAWAN_NET_RESERVE;
bool isTxConfirmed = LORAWAN_UPLINKMODE;
// 2022/1/3 Had to add this to get code to compile. I guessed at value 10
uint8_t confirmedNbTrials = 10;
uint8_t appPort = 10; // for LS2024B payload
#define TIMEOUT 10//time in ms
uint8_t serialBuffer[256];
int size;







char buf[256];
// Compute the MODBUS RTU CRC
uint16_t ModRTU_CRC(uint8_t *  buf, int len)
{
  uint16_t crc = 0xFFFF;
  if (debug) Serial.printf("Entering ModRTU_CRC()..\n");
  
  for (int pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)buf[pos];          // XOR byte into least sig. byte of crc
  
    for (int i = 8; i != 0; i--) {    // Loop over each bit
      if ((crc & 0x0001) != 0) {      // If the LSB is set
        crc >>= 1;                    // Shift right and XOR 0xA001
        crc ^= 0xA001;
      }
      else                            // Else LSB is not set
        crc >>= 1;                    // Just shift right
    }
  }
  // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
  if (debug) Serial.printf("..leaving ModRTU_CRC()\n");
  return crc;  
}

/*
 * Example
 * TX:01 04 31 1d 00 01 af 30
 * RX:0x01, 0x04, 0x02, 0x04, 0xb0, 0xba, 0x44
 */

int readFromRegister( uint16_t address, int size, uint16_t *  buffer ) 
{
  uint8_t   txBuffer[ 16 ];
  uint16_t  crc; 
  
  uint8_t   rxBuffer[ 16 ];
  uint8_t   incomingByte;
  int       rxCount; 
  int       status = 0;

  if (debug) Serial.printf("Entering readFromRegister()..\n");
  if (size > 16) return -1;
  
  // Read data start ing at registerAddress
  txBuffer[ 0 ] = 0x01; // read coils command
  txBuffer[ 1 ] = 0x04; // ??
  txBuffer[ 2 ] = (address >> 8);
  txBuffer[ 3 ] = (address & 0x00FF);  
  txBuffer[ 4 ] = 0;
  txBuffer[ 5 ] = size;  
  crc = ModRTU_CRC( txBuffer, 6 );
  txBuffer[ 6 ] = (crc & 0xFF);  
  txBuffer[ 7 ] = ((crc >> 8) & 0xFF);
     
  if (debug) Serial.printf("\nRequesting %d bytes starting at 0x%04x\n", 
                ((txBuffer[4] * 256) + txBuffer[5])*2,  
                ((txBuffer[2] << 8) + txBuffer[3]) );
  if (debug) {
    for (int i=0; i<8; i++) Serial.printf("%02x ", txBuffer[i] );
    Serial.printf("\n" ); 
  }
  preTransmission();  
  //delay(200);         
  Serial1.write( txBuffer, 8 );
  //delay(1000);
  postTransmission();
  delay(100);
  
  int ignoreFirstNByte = 1; // If not expecting tx chars to be echoed back don't set to 8
  boolean ignoreLastByte = true;
  
  rxCount = 0;
  while ((Serial1.available() > 0) && (rxCount < 50)) {
    // read the incoming byte:
    incomingByte = Serial1.read();
    if (debug) Serial.printf( "%02x, ", incomingByte);
    rxBuffer[ rxCount ] = incomingByte;
    if (ignoreFirstNByte > 0) {
      if (debug) Serial.printf( "WARNING: Ignoring first byte of message 0x%02x\n", incomingByte);
      ignoreFirstNByte--;
      continue; // ignore first byte
    }
    
    if ((rxCount == 0) && (incomingByte != 1)) {
      // Expected response tp be of the form :
      // RX:0x01, 0x04, 0x02, 0x04, 0xb0, 0xba, 0x44
      Serial.printf( "ERROR: Response started with 0x%02x and not 0x01\n", incomingByte);
      status = -1;      
    }
     if ((rxCount == 1) && (incomingByte != 4)) {
      // Expected response tp be of the form :
      // RX:0x01, 0x04, 0x02, 0x04, 0xb0, 0xba, 0x44
      Serial.printf( "ERROR: Response second byte was 0x%02x and not 0x04\n", incomingByte);
      status = -1;      
    }
    
    if ((rxCount == 2) && (incomingByte != (size * 2))) {
      // Expected response to be of the form :
      // RX:0x01, 0x04, 0x02, 0x04, 0xb0, 0xba, 0x44
      Serial.printf( "ERROR: Response had bytes size of 0x%02x and not 0x%02x as expected\n", incomingByte, (size * 2));
      status = -1;
    }    
       
    rxBuffer[ rxCount ] = incomingByte;
    rxCount++;
  }
  delay(200);
  if (rxCount >= 50) {
      if (debug) Serial.printf( "\nERROR: Terminated loop because rcCount(%d) >= 50 bytes\n", rxCount);    
  }
  
  if (ignoreLastByte) {
      if (debug) Serial.printf( "\nWARNING: Ignoring last byte of message 0x%02x\n", incomingByte);
      rxCount--;
  }
  
  if (rxCount != (5 + (2 * size))) {
    // e.g. [01], [04], [02], [00, 01], [78, f0], 
    Serial.printf( "ERROR: Expected %d bytes but received %d\n", (5 + (2 * size)), rxCount );
    status = -1;    
  }
  // If all good let's put the data on the return array
  if (status == 0) { // wasn't set to -1 by a failure
    int j = 0;
    for (int i = 3; i< 3+(2 + size); i += 2) {
      buffer[ j++ ] = (rxBuffer[ i+1 ] << 8) + rxBuffer[ i ];
    }
    status = size;
  }

  if (info) Serial.printf( "INFO: rxCount=%d\n", rxCount);
  
  if (rxCount > 2) {
    // Finally let's check the rx checksum!
    uint16_t rx_crc = ModRTU_CRC( rxBuffer, rxCount-2 );
    uint16_t actual_crc = ((uint16_t)rxBuffer[ rxCount-1  ] << 8) | (uint16_t)rxBuffer[ rxCount-2 ];
    
    if (info) Serial.printf( "INFO: Expect 0x%04x rx checksum and received 0x%04x\n", rx_crc,  actual_crc);
/*
    if (debug) Serial.printf("displaying checksums on OLED display..\n");  
    
    vExtOn();
    delay(100);
    
    display.connect();
    delay(100);    
    
    display.clear(); 
    String row1 = String(rx_crc);  
    String row2 = String(actual_crc);        
    display.drawString(0, 0,  row1 );
    display.drawString(0, 20, row2);
    display.display();
    delay(2000);
    display.clear();

    display.stop();
    delay(100);
    
    vExtOff();     
    delay(100);    
    if (debug) Serial.printf("..displayed\n");
*/          
    if (actual_crc != rx_crc) {
      Serial.printf( "ERROR: Expected 0x%04x rx checksum but received 0x%04x\n", 
           rx_crc,  actual_crc);
      status = -1;       
    }
  }
  if (debug) Serial.printf("..leaving readFromRegister()\n");  
  return status;
}


uint16_t    PV_VOLTAGE    =   0x3100; //(V|100)         Solar charge controller--PV array voltage
uint16_t    PV_CURRENT    =   0X3101; //(A|100)         Solar charge controller--PV array current
uint16_t    PV_POWER_L    =   0x3102; //(W|100)         Solar charge controller--PV array power
uint16_t    PV_POWER_H    =   0x3103; //(W|100)         Solar charge controller--PV array power
uint16_t    BATT_VOLTAGE  =   0x3104; //(V|100)         Battery voltage
uint16_t    BATT_CURRENT  =   0x3105; //(A|100)         Battery charging current
uint16_t    BATT_POWER_L  =   0x3106; //(W|100)         Battery charging power
uint16_t    BATT_POWER_H  =   0x3107; //(W|100)         Battery charging power
// Updated by readLS2024B() and read by prepareTxFrame()
uint16_t    pvV = 0;
uint16_t    pvI = 0;
uint16_t    battV = 0;
uint16_t    battI = 0;
uint16_t    batteryVoltage = 0;
// Accumulated values
uint32_t    pvVLB = 0;
uint32_t    pvILB = 0;
uint32_t    battVLB = 0;
uint32_t    battILB = 0;
uint32_t    batteryVoltageLB = 0;
uint32_t    commsErrors = 0;


#define X_OFFSET 80
// Four measurements with 0.2 sec delay between each so takes about a sec
//
void readLS2024B() {
  int         rxCount;
  uint16_t    rxData[ 16 ];
  boolean     debug = false;
  if (debug) Serial.printf("Entering readLS2024B()..\n");  
  rxCount = readFromRegister( PV_VOLTAGE, 1, rxData );
  if (rxCount > 0) {
    if (debug) Serial.printf( "\nRegister 0x%04x contains 0x%04x\n", PV_VOLTAGE, rxData[0] );
    pvV = 10 * ((rxData[0] & 0x00FF) << 8) + ((rxData[0] & 0xFF00)>> 8);
    if (debug) Serial.printf( "PV_VOLTAGE = %d mV\n", pvV  );
  } else {
    Serial.printf( "\nERROR: reading register 0x%04x\n", PV_VOLTAGE  );
    pvV = 0;
    commsErrors++;     
  }
  /*
  display.clear(); 
  String row2 = String(pvV);        
  display.drawString(0, 0,  "pV (mV)  :" );
  display.drawString(X_OFFSET, 0, row2);
  display.display();
  delay(2000);
  display.clear();
  */
  delay(200);  
    
  rxCount = readFromRegister( PV_CURRENT, 1, rxData );
  if (rxCount > 0) {
    if (debug) Serial.printf( "\nRegister 0x%04x contains 0x%04x\n", PV_CURRENT, rxData[0] );
    pvI = 10 * ((rxData[0] & 0x00FF) << 8) + ((rxData[0] & 0xFF00)>> 8);
    if (debug) Serial.printf( "PV_CURRENT = %d mA\n", pvI  );
  } else {
    Serial.printf( "\nERROR: reading register 0x%04x\n", PV_CURRENT  );
    pvI = 0;
    commsErrors++;     
  }
  /*
  display.clear(); 
  row2 = String(pvI);        
  display.drawString(0, 0,  "pvI (mA) :" );
  display.drawString(X_OFFSET, 0, row2);
  display.display();
  delay(2000);
  display.clear();
  */
  delay(200);  
  
  rxCount = readFromRegister( BATT_VOLTAGE, 1, rxData );
  if (rxCount > 0) {
    if (debug) Serial.printf( "\nRegister 0x%04x contains 0x%04x\n", BATT_VOLTAGE, rxData[0] );
    battV = 10 * ((rxData[0] & 0x00FF) << 8) + ((rxData[0] & 0xFF00)>> 8);
    if (debug) Serial.printf( "BATT_VOLTAGE = %d mV\n", battV  );
  } else {
    Serial.printf( "\nERROR: reading register 0x%04x\n", BATT_VOLTAGE  );
    battV = 0;
    commsErrors++;     
  }
  /*
  display.clear(); 
  row2 = String(battV);        
  display.drawString(0, 0,  "battV (mV):" );
  display.drawString(X_OFFSET, 0, row2);
  display.display();
  delay(2000);
  display.clear();
  */
  delay(200); 
  
  rxCount = readFromRegister( BATT_CURRENT, 1, rxData );
  if (rxCount > 0) {
    if (debug) Serial.printf( "\nRegister 0x%04x contains 0x%04x\n", BATT_CURRENT, rxData[0] );
    battI = 10 * ((rxData[0] & 0x00FF) << 8) + ((rxData[0] & 0xFF00)>> 8);
    if (debug) Serial.printf( "BATT_CURRENT = %d mA\n", battI  );
  } else {
    Serial.printf( "\nERROR: reading register 0x%04x\n", BATT_CURRENT  );
    battI = 0;   
    commsErrors++; 
  }
  /*
  display.clear(); 
  row2 = String(battI);        
  display.drawString(0, 0,  "battI (mA):" );
  display.drawString(X_OFFSET, 0, row2);
  display.display();
  delay(2000);
  display.clear();
  */
  delay(200);  
   
  Serial.printf( "\n");
  if (debug) Serial.printf("..leaving readLS2024B()\n");  
}



// Each reading is accumulated for MAX_TICKS readings then divided by MAX_TICKS before being transmitted.
// 
void  takeMeasurements() {
 
  if (debug) Serial.printf("Entering takeMeasurements()..\n"); 
  
  // Update PV Charge Controller values
  readLS2024B();  
  batteryVoltage = getBatteryVoltage();
  batteryVoltageLB += (uint32_t)batteryVoltage;  
  Serial.printf("CubCell voltage : %d mV  (%d)\n", batteryVoltage, batteryVoltageLB ); 
  
  pvVLB += (uint32_t)pvV; 
  Serial.printf("PV Voltage      : %d mV  (%d)\n", pvV, pvVLB );
  pvILB += (uint32_t)pvI;    
  Serial.printf("PV Current      : %d mA  (%d)\n", pvI, pvILB ); 
  battVLB += (uint32_t)battV; 
  Serial.printf("Battery Voltage : %d mV  (%d)\n", battV, battVLB ); 
  battILB += (uint32_t)battI;  
  Serial.printf("Battery Current : %d mA  (%d)\n", battI, battILB );
  
  Serial.printf("Comms. errors : %d\n", commsErrors ); 
}
  

static void prepareTxFrame( uint8_t port )
{
  if (debug) Serial.printf("Entering prepareTxFrame()..\n"); 
  display.connect();
  vExtOn();  // Turn on display
  delay(100);
  display.init();
  display.setFont(ArialMT_Plain_16); //10, 24
  
 
  String row2 = "";
  
  pvVLB = pvVLB/MAX_TICKS;
  pvILB = pvILB/MAX_TICKS;
  battVLB = battVLB/MAX_TICKS;
  battILB = battILB/MAX_TICKS;
  batteryVoltageLB = batteryVoltageLB/MAX_TICKS;
  
  Serial.printf("PV Voltage      : %d mV\n", pvVLB  );  
  Serial.printf("PV Current      : %d mA\n", pvILB ); 
  Serial.printf("Battery Voltage : %d mV\n", battVLB ); 
  Serial.printf("Battery Current : %d mA\n", battILB );    
  Serial.printf("CubCell voltage : %d mV\n", batteryVoltageLB ); 
  Serial.printf("Comms. errors : %d\n", commsErrors ); 
  
  display.clear(); 
  row2 = String(batteryVoltageLB);        
  display.drawString(0, 0,  "LoRa (mV):" );
  display.drawString(X_OFFSET, 0, row2);
  display.display();
  delay(2000);
  display.clear();
  
  display.clear(); 
  row2 = String(commsErrors);        
  display.drawString(0, 0,  "Comm. Errs:" );
  display.drawString(X_OFFSET+10, 0, row2);
  display.display();
  delay(2000);
  display.clear();
    
  appDataSize = 12;
  appData[0] = highByte(batteryVoltageLB);
  appData[1] = lowByte(batteryVoltageLB);
  appData[2] = highByte(pvVLB);
  appData[3] = lowByte(pvVLB);
  appData[4] = highByte(pvILB);
  appData[5] = lowByte(pvILB);
  appData[6] = highByte(battVLB);
  appData[7] = lowByte(battVLB);
  appData[8] = highByte(battILB);
  appData[9] = lowByte(battILB);
  appData[10] = highByte(commsErrors);
  appData[11] = lowByte(commsErrors);

   
  for( int i=0; i<appDataSize; i++ ) Serial.printf( "0x%02x,", appData[i]);
  Serial.println("");
  vExtOff();   // Turn off display
  display.stop();
  pvVLB = 0;
  pvILB = 0;
  battVLB = 0;
  battILB = 0;
  batteryVoltageLB = 0;
  
}

void vExtOn() {
    pinMode(Vext,OUTPUT);
    digitalWrite(Vext, LOW);
}
void vExtOff() {
    pinMode(Vext,OUTPUT);
    digitalWrite(Vext, HIGH);
}
int tickCounter = 0;
void setup()
{
  boardInitMcu();
  // Serial 1 TX1, RX1 is used for programming and monitor debug output...
  Serial.begin(9600);
  while (!Serial) { ; }
  // Serial 2 TX2, RX2 is used for RS485 comms...
  Serial1.begin(115200);
  while (!Serial) { ; }
  
  Serial.printf("\n\nSketch=%s, version=%s\n", SKETCH_NAME, VERSION);

  // Initialising the UI will init the display too.
  //display(0x3c, 500000, SDA, SCL ,GEOMETRY_128_64,GPIO10); // addr, freq, sda, scl, resolution, rst
  vExtOn();
  delay(100);
    
  display.init();
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  //  "Cubecell_PV_epever_monitor_slan-032_v1.16"
  String title = SKETCH_NAME;
  int index = title.indexOf("-")-4;
  display.drawString(0, 0, title.substring(1, index));
  display.drawString(0, 20, title.substring(index));
  display.drawString(0, 40, VERSION);
  display.display();
  delay(5000);
  display.clear();
  
  vExtOff(); // turn off display
  display.stop(); 
   
  pinMode(MAX485_RE, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_RE, 0);  // Receiver Enable LOW to receive
  digitalWrite(MAX485_DE, 0);  // Driver Enable HIGH to transmit
  
  deviceState = DEVICE_STATE_INIT;
  LoRaWAN.ifskipjoin();
  tickCounter = (MAX_TICKS - 1);  // So we can test LoRaWAN transmission right after a reset
}


// Every time round the loop we take measurents
// but every 5 mins we send them over LoRaWAN
//
boolean looping = true;
void loop() {
  if (debug) Serial.printf("Entering loop()..\n");  
  tickCounter++;
  takeMeasurements(); // Takes about a second
  
  if (tickCounter == MAX_TICKS) {
    deviceState = DEVICE_STATE_INIT;
    tickCounter = 0;
    looping = true;    
    if (looping) {
      while(deviceState != DEVICE_STATE_CYCLE) {
        // Transmit the data but don't let it deep sleep
        transmitLoop(); // resets accumulated readings as well
      }
      
      int period = 30;
      Serial.printf("Delaying %d secs in state DEVICE_STATE_CYCLE to let LoRaWAN transmission take place..\n", period);
      delay(period * 1000); // Delay 10 secs for sending
    }
  }
  delay(LOOP_DELAY_MSECS); 
}
void transmitLoop()
{
  if (debug2) Serial.printf("deviceState=%d\n", deviceState);
  switch( deviceState )
  {
    case DEVICE_STATE_INIT:
    {
      if (debug2) Serial.printf("deviceState = DEVICE_STATE_INIT(%d)\n",deviceState);
      if (debug2) printDevParam();
      LoRaWAN.init(loraWanClass,loraWanRegion);
      deviceState = DEVICE_STATE_JOIN;
      break;
    }
    case DEVICE_STATE_JOIN:
    {
      if (debug2) Serial.printf("deviceState = DEVICE_STATE_JOIN(%d)\n",deviceState );      
      LoRaWAN.join();
      break;
    }
    case DEVICE_STATE_SEND:
    {
      if (debug2) Serial.printf("deviceState = DEVICE_STATE_SEND(%d)\n",deviceState );      
      prepareTxFrame( appPort );
      LoRaWAN.send();
      deviceState = DEVICE_STATE_CYCLE;
      break;
    }
    case DEVICE_STATE_CYCLE:
    {
      if (debug2) Serial.printf("deviceState = DEVICE_STATE_CYCLE(%d)\n",deviceState );      
      // Schedule next packet transmission
      txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
      LoRaWAN.cycle(txDutyCycleTime);
      deviceState = DEVICE_STATE_SLEEP;
      break;
    }
    case DEVICE_STATE_SLEEP:
    {
      if (debug2) Serial.printf("deviceState = DEVICE_STATE_SLEEP(%d)\n",deviceState ); 
      looping = false;
      break;     
      //LoRaWAN.sleep();
      //break;
    }
    default:
    {
      if (debug) Serial.printf("deviceState = default(%d)\n",deviceState );      
      deviceState = DEVICE_STATE_INIT;
      break;
    }
  }
}

Below is the output from a run





(Last updated Thurs 5th May 2022 18:17)










Friday, 29 April 2022

Using a NodeMCU to monitor an eSmart3 charge controller



The wiring is as follows:


From: https://skagmo.com/page.php?p=documents/04_esmart3_review
Extra: RS485 port
The pinout on this port is as follows:
Pin Function
1 RS-485 A/+
2 RS-485 B/-
5,6 GND
7,8 +5V out

Looking at the RJ-45 plug end on (towards you) with the retaining clip at the bottom the wiring is:


Pin Number:              8               7                  6            5                 4             3              2                1    

Cable Colour:        brown        brown /       green        blue /       blue       green /        orange      orange /
                                                 white                           white                     White                          white

Function:                  +5v         +5v            GND          GND                                             B              A

           

So first let's do a baseline test using PC software and A/B wired to a RS485 to USB adaptor.


All worked OK.


tele/nodemcu_pv_charger/pv_volt

70.70







The Arduino code was based on..

Saturday, 23 April 2022

Experienting with lead acid batteries in Tola

 I have 8x 100W solar panels on my pergola and brought down my eSmart3 charge controller and 2x 12v 70Ah lead acid batteries.

I intend to set up a little mains supply system in the kitchen with a 300W inverter I have knocking around :)





Thursday, 21 April 2022

Experimenting with two 24v 100Ah LiFePO4 batteries in Kilnageer

For the last few days I've been testing my two 24v 100Ah LiFePO4 batteries.

I received them a few weeks ago but only tested BLE communications to their BMS with an Android App. I didn't try charging or discharging them.

I bought them on Jan 11, 2022 from  CERRNSS Battery Factory Store (https://www.aliexpress.com/store/912104017) on AliExpress and they cost 1,311 euros including all taxes and a mains charger. I specifically asked for them to have Wi-Fi access to their BMS. They arrived on the 1st April, 2022 so took 10 or so weeks to arrive.

But after taking them up to Mayo on Mon 18th April 2022 the testing finally began.


In Mayo I have 5x 230W solar PV panels connected to a eSmart3 charge controller which was connected to 6x lead acid leisure batteries (configured as three 24v pairs in parallel).







Wednesday, 6 April 2022

Wood delivered for pergola and PV panel stand

 The idea is the pergola will hold two vines and eventually have solar PV panels on top.



Built pergola which has three 4 foot (48" / 1220 mm) by 3 foot (36" / 920 mm) sections for solar panels. Can I get 300+ W ones to fit in there?





Friday, 1 April 2022

Finally got my LiPo Batteries from China

 Happy days my batteries have arrived




Exciting unboxing them!



These are 24v 100Ah LiPo batteries so combined provide 4.8 KWh (or 5 units) of electricity.

I expect only 80% can be drawn. I also have a mains charger for them.

So either I charge them at a night rate in Tola and discharge during the day to reduce my electricity bill. But Community Power haven't implemented my night rate yet.

Or take them to Mayo and see if they can supply enough current @24V to my 4KW inverter so that I can run the oven for an hour (2KWh). Something I'm yet to achieve.

I also downloaded the Android BMS app to talk over  low-power Bluetooth (BLE) to each battery's Battery Management System (BMS) and all looks good.

https://drive.google.com/drive/folders/1CXmg5qO9P9VHWR4YZBSQSR12QE1Lp9Xw


They appear to by 8 strings of 3.x v LiPo batteries.



But I want to do this monitoring using a NodeMCU and Arduino later.






















Friday, 25 March 2022

Photo resistor (2x) and transistors (10x TIL78) have arrived

 Got back from Mayo to two packages containing my photo resistors and transistors.


Aim to use theses to detect the LED pulses from OMNIpower smart electricity meter


Looks like a 47KR will do the trick according to this website:

https://forum.arduino.cc/t/phototransistor-usage/190418/10

https://learn.parallax.com/tutorials/robot/shield-bot/robotics-board-education-shield-arduino/chapter-6-light-sensitive-15

Long lead is collector C and shorted lead is emitter E

A 5v to C and a 2KR from E to GND with A/D sampling at E pin should do this trick :)





Once I've determined the voltages I can refine the Arduino sketch 






Tuesday, 1 March 2022

Setting up two ESPNow boards

I used the  two TTGO ESP32 LoRa boards to experiment with ESPNow communications. Which I haven't tried yet.

Master code serial output:

STA MAC: 4C:75:25:C2:7F:3C
ESPNow Init Success
 
Found 18 devices 
Slave Not Found, trying again.
 
Found 23 devices 
Slave Not Found, trying again.
 
Found 13 devices 
Slave Not Found, trying again. 
 

Slave code serial output:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8
ESPNow/Basic/Slave Example
AP Config Success. Broadcasting with AP: Slave_1
AP MAC: 4C:75:25:C2:EF:CD
ESPNow Init Success  


Would like OLED display support in Arduino so I can do a field range test :) Llooking for a suitable library :)

https://github.com/LilyGO/TTGO-LORA32

 

I went for the library from:

https://github.com/ThingPulse/esp8266-oled-ssd1306

And the OLED sketch:

/home/kilnageer/Arduino/sketches/LILYGO TTGO ESP32 LoRa OLED/TTGO-LORA32/BaT_test_ssd1306/BaT_test_ssd1306.ino 


 

which worked great! So combining the two sketches I now get..



 

 

 

 



Monday, 28 February 2022

Programming a TTGO ESP32 as a 868MHz RF sniffer

Out of the box the MCU runs a person counter programmer called PAXCOUNTER. Which uses bluetooth and WiFi transmissions to detect how many people are nearby.

http://www.lilygo.cn/prod_view.aspx?TypeId=50060&Id=1271&FId=t3:50060:3



And produces this serial output at 115200 baud on its micro-USB connector.

kilnageer@mint-AMILO-Pro-Series-V8210:~/Downloads/arduino-1.8.19$ cat putty.log
=~=~=~=~=~=~=~=~=~=~=~= PuTTY log 2022.02.27 22:22:46 =~=~=~=~=~=~=~=~=~=~=~=
.cpp:110] sendData(): Counter cleared
ery: 4230mV
[I[I][cyclic.cpp:73] doHousekeeping(): Battery: 4200mV
[I][senddata.cpp:110] sendData(): Counter cleared
[I][cyclic.cpp:73] doHousekeeping(): Battery: 4198mV
[I][cyclic.cpp:73] doHousekeeping(): Battery: 4266mV
[I][senddata.cpp:110] sendData(): Counter c.cpp:110] sendData(): Counter cleared
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:928
ho 0 tail 12 room 4
load:0x40078000,len:8740
load:0x40080400,len:5788
entry 0x4008069c
[I][reset.cpp:64] do_after_reset(): Starting Software v1.9.982, runmode 0
[I][configmanager.cpp:190] loadConfig(): Reading settings from NVS
[I][configmanager.cpp:55] open_storage(): Opening NVS
[I][configmanager.cpp:60] open_storage(): Done
[I][configmanager.cpp:204] loadConfig(): NVRAM settings version = 1.9.982
[I][configmanager.cpp:222] loadConfig(): bsecstate = 0
[I][configmanager.cpp:227] loadConfig(): loradr = 5
[I][configmanager.cpp:235] loadConfig(): txpower = 14
[I][configmanager.cpp:243] loadConfig(): adrmode = 1
[I][configmanager.cpp:251] loadConfig(): screensaver = 0
[I][configmanager.cpp:259] loadConfig(): screenon = 1
[I][configmanager.cpp:267] loadConfig(): countermode = 0
[I][configmanager.cpp:275] loadConfig(): sendcycle = 30
[I][configmanager.cpp:283] loadConfig(): wifichancycle = 50
[I][configmanager.cpp:291] loadConfig(): wifiantenna = 0
[I][configmanager.cpp:299] loadConfig(): vendorfilter = 1
[I][configmanager.cpp:307] loadConfig(): rgbluminosity = 30
[I][configmanager.cpp:315] loadConfig(): blescantime = 8
[I][configmanager.cpp:323] loadConfig(): BLEscanmode = 0
[I][configmanager.cpp:331] loadConfig(): WIFIscanmode = 1
[I][configmanager.cpp:339] loadConfig(): rssilimit = 0
[I][configmanager.cpp:347] loadConfig(): payloadmask = 127
[I][configmanager.cpp:355] loadConfig(): Monitor mode = 0
[I][configmanager.cpp:362] loadConfig(): Done
[I][i2c.cpp:23] i2c_scan(): Starting I2C bus scan...
[I][i2c.cpp:44] i2c_scan(): 0x3C: SSD1306 Display controller
[I][i2c.cpp:71] i2c_scan(): I2C scan done, 1 devices found.
[I][main.cpp:242] setup(): Starting LED Controller...
[I][power.cpp:171] calibrate_voltage(): ADC characterization based on reference voltage stored in eFuse
[I][lorawan.cpp:297] lora_stack_init(): LORA send queue created, size 600 Bytes
[I][lorawan.cpp:300] lora_stack_init(): Starting LMIC...
[I][main.cpp:375] setup(): Starting Wifi...
[I][main.cpp:388] setup(): Starting Interrupt Handler...
[I][main.cpp:412] setup(): Starting Timers...
[I][main.cpp:470] setup(): Starting Timekeeper...
[I][timekeeper.cpp:151] timepulse_init(): Timepulse: internal (ESP32 hardware timer)
[I][timesync.cpp:52] timesync_request(): [10.506] Timeserver sync request seqNo#144 started
[I][main.cpp:477] setup(): Features: OLED LED BATT OTA LORA FILTER PACKED WIFI
[I][cyclic.cpp:73] doHousekeeping(): Battery: 4116mV
kilnageer@mint-AMILO-Pro-Series-V8210:~/Downloads/arduino-1.8.19$ date
Sun 27 Feb 22:23:58 GMT 2022
kilnageer@mint-AMILO-Pro-Series-V8210:~/Downloads/arduino-1.8.19$


Which while interesting is of no use to this RF sniffer project.

To use the Arduino IDE for this MCU you need to add  https://dl.espressif.com/dl/package_esp32_index.json into the “Additional Board Manager URLs” field in the File -> Preferences screen.

Then install/download the 32MByte esp32 board support package by Espressif in the Board Manager (see https://github.com/espressif/arduino-esp32)

(See https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/)

After this you can select the "TTGO  LoRa32-OLED v2.1.6" board via Tools -> Board

In passing, I had to follow http://playground.arduino.cc/Linux/All#Permission to get serial monitor access

No good couldn't compile without getting below error. I also tried using board "Heltec WiFi LoRa 32" as stated in:

https://github.com/LilyGO/ESP32-Paxcounter/blob/master/platformio.ini

 

Traceback (most recent call last):
  File "/home/kilnageer/.arduino15/packages/esp32/tools/esptool_py/3.0.0/esptool.py", line 38, in <module>
    import serial
ImportError: No module named serial
exit status 1
Error compiling for board Heltec WiFi LoRa 32.

kilnageer@mint-AMILO-Pro-Series-V8210:~/platformio/ESP32-Paxcounter$ pip install pyserial
Collecting pyserial
  Using cached https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl
Installing collected packages: pyserial
Successfully installed pyserial-3.5
kilnageer@mint-AMILO-Pro-Series-V8210:~/platformio/ESP32-Paxcounter$ 

That fized above arduino serial issue and can now program MCU with blink, WiFiscan, etc. sketches :)


So tried using PlatformIO Core (CLI) (I'm on a 32-bit Mint Linux laptop so VSC, etc won't install!)

Wouldn't compile.. missing bt_xxx.h file.

 pio run

..


Compiling .pio/build/ttgov2/src/blecsan.cpp.o
Compiling .pio/build/ttgov2/src/lorawan.cpp.o
src/blecsan.cpp:15:22: fatal error: bt_types.h: No such file or directory

******************************************************************
* Looking for bt_types.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:bt_types.h"
* Web  > https://registry.platformio.org/search?q=header:bt_types.h
*
******************************************************************

compilation terminated.


 







 

 



 LILYGO TTGO ESP32-Paxcounter LoRa32 V2.1 1.6.1 Version 868MHZ LoRa ESP-32 OLED 0.96 Inch SD Card Bluetooth WIFI Module(868MHz CH9102)
Sold by TIAN YI

 

Mimicking a Friedland Doorbell

The project goal is to ring an existing Friedland doorbell when the Ring Doorbell 4 is pressed. 

To this end I used an SDR (Software Defined Radio) USB dongle to see if it could pick up bell rings on 868 MHz. 

Looking at the back of the doorbell is has the Libra+ model number of : 48248SL and the fact it operates at 868Mz (the unlicensed instrumentation band in the UK/Ireland)

With the rtl_433 software installed on a Kali Linux desktop I got this result: 

 

Using the command:

kilnageer@mint-AMILO-Pro-Series-V8210:~$ rtl_433 -v -f 868000000 -M time

Interestingly, it sees it as a Honeywell doorbell so they must share the same RF protocol! 

So this allows me to know when someone has pressed the doorbell but can I mimic this action myself in software so that I can get the Ring doorbell to activate it? 

So to this end I bought a Honeywell ringer and a LILYGO TTGO MCU both of which have 868MHz transmitters.

The Honeywell DCP311 doorbell push button:




uses the ActivLink protocol but isn't detected by the SDR. So I've parked that approach up for now to concentrate on the TTGO MCU. Which can apparently run sniffer firmware :)

http://www.lilygo.cn/prod_view.aspx?TypeId=50060&Id=1271&FId=t3:50060:3

So my next blog post will be on this device.


 

 

Sunday, 6 February 2022

ST-Link V2 Programming Unit mini STM8 STM32 Emulator Downloader M89 New Total: EUR 10.95

 Bought this on 6/2/22 for 11 euros. Hopefully it will allow me to reprogramme ST controller that Lets Talk Solar installed.

RC Boat Ready to Test at Wetlands

 I dropped the resistor down to 900R from 2K2R and the motor now comes on reliably. See YouTube video.


https://youtu.be/SGTJCwVKb_8



Wednesday, 2 February 2022

RC Boat for Wetlands switched to Power Transistors

Experiments with SG90 servos and board resulted in failure to drive the motors.

http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf


So rummaged around in component boxes until I found some power transistors.

The 2N3054 should do the trick:

https://octopart.com/datasheet/2n3054-comset+semiconductors-29378570

https://www.homemade-circuits.com/dc-motor-speed-controller-circuits/


I ended up with a diode across the motor with both between th NPN collector (case) and +5v from a USB power bank. Then a 2K2R resistor from base pin to micro:bit and emitter connected to GND.

Also have a red LED (longer lead to +5v) and 670R resistor across water pump motor as a visual indication.

With the NPN viewed from behind with the two pins furthest away from you the emitter is on the right (with base on the left)




Next, after testing successfully using a breadboard last night, 


I decided to commit two channels to a veroboard this morning.




Got one wired and works if signal in connected to +5v (i.e. LED and motor turn on) but not when driven by 3.5v signal from micro:bit! Strange as this worked on the breadboard last night!

After some fiddling it finally worked. So loose cable maybe? Now wiring up the second transistor.

Got second channel working (LED on when signal taken to +5v) but first channel now broken!

Fixed. Was loose solder to collector casing.





















Sunday, 30 January 2022

Making a radio controlled boat to take environmental readings at the Shannon Wetlands

So this is an activity which I though would inspire young people to get involved in taking and processing environment data.

It's goal is to making a boat that can carry environmental sensors to the centre of the Shannon Wetlands ponds.

My thinking being two fish tank water pumps could be the motors with their power controlled by a BBC micro:bit which could receive commands remotely from another micro:bit. The boat could be made of cardboard which is waterproofed by gaffer tape. The motor control board and code from the Kitronix Move mini robot could be re-used.

So it composes of 5 elements:

1) A waterproof hull (cardboard covered with black plastic gaffer tape)

2) A motor (two water pumps taped to the rear of the boat)

3) A receiver that controls the motors (a BBC micro:bit and motor board from a Kitronix Move)

4) A power source on the boat (a 5v USB power bank)

5) A remote control (another BBC micro:bit using tilt control for direction / speed / full stop)


The code had to provide individual power control to two submersed water pumps which provide propulsion for the boat. That is 100% power to both pumps is full steam ahead, 0% to both is full stop and 100% to left pump (starboard) and 0% to right pump (port) would turn the boat left, etc.

The MOVE mini code is a good starting point:


The Kitronix MOVE mini: https://kitronik.co.uk/products/5624-move-mini-buggy-kit-excl-microbit.html

The Servo:Lite motor board can drive up to 1A: https://resources.kitronik.co.uk/pdf/5623-servo-lite-datasheet.pdf

Library to control motor board: https://github.com/KitronikLtd/pxt-kitronik-servo-lite

Looking at their the servos what VCC, GND amd Cobtrol. And looking at the GIT library code this Control wire is drive by:

    export function forward(): void {

        pins.servoWritePin(AnalogPin.P1, 0);

        pins.servoWritePin(AnalogPin.P2, 180);

    }


    export function backward(): void {

        pins.servoWritePin(AnalogPin.P1, 180);

        pins.servoWritePin(AnalogPin.P2, 0);

    }


    export function left(): void {

        pins.servoWritePin(AnalogPin.P1, 0);

        pins.servoWritePin(AnalogPin.P2, 0);

    }

    export function right(): void {

        pins.servoWritePin(AnalogPin.P1, 180);

        pins.servoWritePin(AnalogPin.P2, 180);

    }

    export function stop(): void {

        pins.analogWritePin(AnalogPin.P1, 0);

        pins.analogWritePin(AnalogPin.P2, 0);

    }

    export function neutral(): void {

        pins.servoWritePin(AnalogPin.P1, 90);

        pins.servoWritePin(AnalogPin.P2, 90);

    }


So this the analogue voltage presented to P1 and P2 controls the servo motor.

https://www.ebay.co.uk/itm/284556271865


http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf


But for the boat I just want a voltage!




Parts list:

1) 2x DC 2.5V / 6V Small Mini Water Pump Fish Tank Fountain Aquarium Micro Submersible bought from ebay.ie for £3.50 each.

2) Re-used guts of https://kitronik.co.uk/products/5652-move-mini-mk2-buggy-kit-excl-microbit

3) Cardboard and black duck tape

4) 2x BBC micro:bit

5) 2x 5v USB power banks (from Dealz for 1.50 euro each)











Measuring Electricty Usage

The simplest way is to just read your meter and log the results. (Hopefully, eventually, the new smart meters will allow people to do that electronically!)

A less time consuming way is to install a monitor.

Though you will always need to check and apply a fudge factor to the readings from the monitor so it agrees with your true meter reading.

OK. So how do we go about all this?

Well, if you look at your electricity bills you will see your usage over the billing period (typically every one or two months).

Here's the values for a 3 bed semi in Shannon Town:

Bill

Start

Reading

Type

End

Reading

Type

Usage

15/12/20

01/11/20

92782

E

30/11/20

105

E

260.56

12/01/21

01/12/20

105

E

31/12/20

213

E

107.37

10/02/21

01/01/21

213

E

31/01/21

473

E

260.66

11/03/21

01/02/21

473

E

28/02/21

705

E

231.26

12/04/21

01/03/21

705

E

31/03/21

946

E

241.35

11/05/21

01/04/21

946

E

30/04/21

1314

E

368.30

14/06/21

01/05/21

1314

E

31/05/21

1531

E

217.04

12/07/21

01/06/21

1531

E

31/06/21

1782

E

251.03

11/08/21

01/07/21

1782

E

31/07/21

1992

E

209.20

08/09/21

01/08/21

1992

E

14/08/21

2091

E

99.09

13/09/21

15/08/21

2091

E

31/08/21

2167

E

76.72

12/10/21

01/09/21

2167

E

30/09/21

2385

E

217.20

12/11/21

01/10/21

2385

E

31/10/21

2490

E

104.98

15/12/21

01/11/21

2490

E

30/11/21

2729

E

238.94

13/01/22

01/12/21

2729

E

31/12/21

2903

E

174.78


And for a 5 bed detached single story cottage in the Mayo countryside.

Bill

Start

Reading

Type

Interim

Reading

Type

End

Reading

Type

Usage

16/12/20

16/10/20

61391

E

15/12/20

62092

A

16/12/20

62150

E

714

16/02/21

16/12/20

62105

E

20/12/20

62141

C

16/02/21

62659

E

554

16/04/21

16/02/21

62659

E




16/04/21

63139

E

480

16/06/21

16/04/21

63139

E

10/05/21

63918

C

16/06/21

64337

E

1198

16/08/21

16/06/21

64337

E

18/06/21

64456

A

12/08/21

65066

C

729

16/10/21

12/08/21

65066

C




16/10/21

65830

E

764

16/12/21

16/10/21

65830

E




13/12/21

67102

A

1272


So what next? Well what about heating oil usage?


So what does all this say? Well if you average the amount of oil (one litre of kerosene is approx. 9 units) and electricity used you find this is the average daily energy usage over the year 2021:

Shannon:

Mayo:


Now with technology all of this monitor and logging can be done automatically with a physical check every month of so to ensure its accuracy.