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)