Sorry for the delay - not sure how I missed this post.
I did get it to work, and it has been in service successfully for a few months now. I am not a professional coder, so it is sloppy - but it does work. The code is copied below.
Note that the orientation of the sensor does matter. If you have yours mounted differently than mine you may need to monitor/trigger off a different axis than I do.
The way I did it is basically an “open” and “closed” with a deadband in the middle. To add the deadband so it didn’t flip-flip while the door was opening/closing (as there is a lot of vibration and shaking) I had to do it with 2 different interrupts and movement check routines.
No matter how I tuned it, I kept getting false open/closed events if trying to do it with a single interrupt.
Arduino Code
#include <SparkFunLIS3DH.h>
#include <Wire.h>
// ******************************************************************************************************
// Uncomment the define below to get logging. Re-comment before putting in production to save battery.
// ******************************************************************************************************
//#define LOGSTUFF
#define SMART_SENSOR_PERIOD (43200000)
#define SMART_SENSOR_BAND (RAK_REGION_US915)
#define SMART_SENSOR_APPEUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
// ******************************************************************************************************
// Enter your device info here, or input without hard coding it using bluetooth, et al.
// Note you would need to change bluetooth STOP logic in setup if using bluetooth.
// ******************************************************************************************************
#define SMART_SENSOR_DEVEUI {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
#define SMART_SENSOR_APPKEY {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
/** 3 Axis Sensor **/
LIS3DH Sensor( I2C_MODE, 0x18 );
/** Packet buffer for sending */
uint8_t collected_data[64] = { 0 };
/** App Variables */
unsigned long lastMillis = 0;
unsigned long currentMillis;
unsigned long deltaTimeReportMax = 43200000; //12 Hours
uint8_t lastReport = 99;
void recvCallback(SERVICE_LORA_RECEIVE_T * data)
{
if (data->BufferSize > 0) {
#ifdef LOGSTUFF
Serial.println("Something received!");
#endif
for (int i = 0; i < data->BufferSize; i++) {
#ifdef LOGSTUFF
Serial.printf("%x", data->Buffer[i]);
#endif
}
#ifdef LOGSTUFF
Serial.print("\r\n");
#endif
}
}
void joinCallback(int32_t status)
{
#ifdef LOGSTUFF
Serial.printf("Join status: %d\r\n", status);
#endif
}
void sendCallback(int32_t status)
{
if (status == 0) {
#ifdef LOGSTUFF
Serial.println("Successfully sent");
#endif
} else {
#ifdef LOGSTUFF
Serial.println("Sending failed");
#endif
}
}
void setup()
{
#ifdef LOGSTUFF
Serial.begin(115200, RAK_AT_MODE);
delay(10000);
Serial.println("------------------------------------------------------");
Serial.println("RAKwireless RAK1904 RUI3");
Serial.println("------------------------------------------------------");
delay(5000);
#endif
//Stop BLE
api.ble.uart.stop();
// OTAA Device EUI MSB first
uint8_t node_device_eui[8] = SMART_SENSOR_DEVEUI;
// OTAA Application EUI MSB first
uint8_t node_app_eui[8] = SMART_SENSOR_APPEUI;
// OTAA Application Key MSB first
uint8_t node_app_key[16] = SMART_SENSOR_APPKEY;
if (!api.lorawan.appeui.set(node_app_eui, 8)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set application EUI is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.appkey.set(node_app_key, 16)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set application key is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.deui.set(node_device_eui, 8)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set device EUI is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.band.set(SMART_SENSOR_BAND)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set band is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set device class is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.njm.set(RAK_LORA_OTAA)) // Set the network join mode to OTAA
{
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set network join mode is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.join()) // Join to Gateway
{
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - join fail! \r\n");
#endif
return;
}
#ifdef LOGSTUFF
Serial.println("++++++++++++++++++++++++++");
Serial.println("RUI3 Tilt Sensing");
Serial.println("++++++++++++++++++++++++++");
#endif
// Configure Tilt Sensor
Sensor.begin();
Sensor.settings.accelSampleRate = 1; //Hz. Can be: 0,1,10,25,*50*,100,200,400,1600,5000 Hz
Sensor.settings.accelRange = 2; //Max G force readable. Can be: 2, 4, 8, 16
Sensor.settings.adcEnabled = 0;
Sensor.settings.tempEnabled = 0;
Sensor.settings.xAccelEnabled = 0;
Sensor.settings.yAccelEnabled = 0;
Sensor.settings.zAccelEnabled = 1;
//LIS3DH_INT1_CFG
uint8_t dataToWrite = 0;
dataToWrite |= 0x20;//Z high
Sensor.writeRegister(LIS3DH_INT1_CFG, dataToWrite);
delay(100);
//LIS3DH_INT1_THS
dataToWrite = 0;
dataToWrite |= 0x20; // 0x20 = 512mg @ 2G range
Sensor.writeRegister(LIS3DH_INT1_THS, dataToWrite);
delay(100);
//LIS3DH_INT1_DURATION
dataToWrite = 0;
dataToWrite |= 0x08;
Sensor.writeRegister(LIS3DH_INT1_DURATION, dataToWrite);
delay(100);
//LIS3DH_INT2_CFG
dataToWrite = 0;
dataToWrite |= 0x10;//Z low
Sensor.writeRegister(0x34, dataToWrite);
delay(100);
//LIS3DH_INT2_THS
dataToWrite = 0;
dataToWrite |= 0x10; // 0x10 = 1/8 range
Sensor.writeRegister(0x36, dataToWrite);
delay(100);
//LIS3DH_INT2_DURATION
dataToWrite = 0;
dataToWrite |= 0x08;
Sensor.writeRegister(0x37, dataToWrite);
delay(100);
//LIS3DH_CTRL_REG0
// Turn off pullup resistor to save power
dataToWrite = 0;
dataToWrite |= 0x90;
Sensor.writeRegister(0x1E, dataToWrite);
delay(100);
//LIS3DH_CTRL_REG1
// Low Power Mode
Sensor.readRegister(&dataToWrite, LIS3DH_CTRL_REG1);
dataToWrite |= 0x08; // Set Low Power Mode
Sensor.writeRegister(LIS3DH_CTRL_REG1, dataToWrite);
delay(100);
//LIS3DH_CTRL_REG3
//Choose source for pin 1
dataToWrite = 0;
dataToWrite |= 0x40; //AOI1 event (Generator 1 interrupt on pin 1)
Sensor.writeRegister(LIS3DH_CTRL_REG3, dataToWrite);
delay(100);
//LIS3DH_CTRL_REG5
Sensor.readRegister(&dataToWrite, LIS3DH_CTRL_REG5);
dataToWrite = 0;
dataToWrite &= 0x78; //Clear bits of interest
Sensor.writeRegister(LIS3DH_CTRL_REG5, dataToWrite);
delay(100);
//LIS3DH_CTRL_REG6
dataToWrite = 0;
dataToWrite |= 0x20; // I2_IA2 -- works
Sensor.writeRegister(LIS3DH_CTRL_REG6, dataToWrite);
delay(100);
// I do it a second time to make sure it took. Might not be necessary.
//LIS3DH_CTRL_REG0
// Turn off pullup resistor to save power
dataToWrite = 0;
dataToWrite |= 0x90;
Sensor.writeRegister(0x1E, dataToWrite);
delay(100);
// Mini Base Slot D IO = WB_IO5
pinMode(WB_IO5, INPUT);
delay(100);
attachInterrupt(WB_IO5, movement1, CHANGE);
delay(100);
pinMode(WB_IO6, INPUT);
delay(100);
attachInterrupt(WB_IO6, movement2, CHANGE);
delay(100);
/** Wait for Join success */
while (api.lorawan.njs.get() == 0) {
#ifdef LOGSTUFF
Serial.print("Wait for LoRaWAN join...");
#endif
api.lorawan.join();
delay(10000);
}
if (!api.lorawan.adr.set(true)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set adaptive data rate is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.rety.set(1)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set retry times is incorrect! \r\n");
#endif
return;
}
if (!api.lorawan.cfm.set(0)) {
#ifdef LOGSTUFF
Serial.printf("LoRaWan Smart Sensor - set confirm mode is incorrect! \r\n");
#endif
return;
}
/** Check LoRaWan Status*/
#ifdef LOGSTUFF
Serial.printf("Duty cycle is %s\r\n", api.lorawan.dcs.get()? "ON" : "OFF"); // Check Duty Cycle status
Serial.printf("Packet is %s\r\n", api.lorawan.cfm.get()? "CONFIRMED" : "UNCONFIRMED"); // Check Confirm status
#endif
uint8_t assigned_dev_addr[4] = { 0 };
api.lorawan.daddr.get(assigned_dev_addr, 4);
#ifdef LOGSTUFF
Serial.printf("Device Address is %02X%02X%02X%02X\r\n", assigned_dev_addr[0], assigned_dev_addr[1], assigned_dev_addr[2], assigned_dev_addr[3]); // Check Device Address
Serial.printf("Uplink period is %ums\r\n", SMART_SENSOR_PERIOD);
Serial.println("");
#endif
api.lorawan.registerRecvCallback(recvCallback);
api.lorawan.registerJoinCallback(joinCallback);
api.lorawan.registerSendCallback(sendCallback);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void movement1()
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{
uint8_t dataRead;
currentMillis = millis();
#ifdef LOGSTUFF
Serial.println("\r\n");
Serial.println("---------------------------------------------------");
Serial.println("Movement 1 report");
Serial.println("---------------------------------------------------");
Serial.printf("Current millis: ");
Serial.println(currentMillis);
Serial.printf("Last millis: ");
Serial.println(lastMillis);
Serial.printf("Last Report: ");
Serial.println(lastReport);
#endif
if (lastReport == 1) {
#ifdef LOGSTUFF
Serial.println("lastReport is one. Exiting.");
#endif
return;
}
#ifdef LOGSTUFF
Serial.println("lastReport is not one. Continuing.");
#endif
Sensor.readRegister(&dataRead, LIS3DH_INT1_SRC);
#ifdef LOGSTUFF
Serial.print("Data read: ");
Serial.println(dataRead);
#endif
#ifdef LOGSTUFF
Serial.print("dataRead & 0x20 :");
Serial.println(dataRead & 0x20);
Serial.print("dataRead & 0x10 :");
Serial.println(dataRead & 0x10);
#endif
if (dataRead & 0x20) {
// Continue on with the loop
} else{
#ifdef LOGSTUFF
Serial.println("Not right status. Exiting.");
#endif
return;
}
lastMillis = currentMillis;
lastReport = 1;
uint16_t batt = (uint16_t)(api.system.bat.get() * 1000);
#ifdef LOGSTUFF
Serial.printf("battery %.2f\r\n", (float)batt);
Serial.printf("Battery Level: %f\r\n", api.system.bat.get());
#endif
/** Cayenne Low Power Payload */
uint8_t data_len = 0;
collected_data[data_len++] = 0x01; //Data Channel: 1 //1
collected_data[data_len++] = 0x00; //Type: Digital Input //2
collected_data[data_len++] = 1; //3
collected_data[data_len++] = 0x02; //Data Channel: 2 //4
collected_data[data_len++] = 0x02; //Type: Analog Input //5
collected_data[data_len++] = (uint8_t)(batt >> 8); //6
collected_data[data_len++] = (uint8_t)batt; //7
/** Send the data package */
if (api.lorawan.send(data_len, (uint8_t *) & collected_data, 2, false, 1)) {
#ifdef LOGSTUFF
Serial.println("Sending is requested");
#endif
} else {
#ifdef LOGSTUFF
Serial.println("Sending failed");
#endif
}
//api.system.sleep.all(deltaTimeReportMax);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void movement2()
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{
uint8_t dataRead;
currentMillis = millis();
#ifdef LOGSTUFF
Serial.println("\r\n");
Serial.println("---------------------------------------------------");
Serial.println("Movement 2 report");
Serial.println("---------------------------------------------------");
Serial.printf("Current millis: ");
Serial.println(currentMillis);
Serial.printf("Last millis: ");
Serial.println(lastMillis);
Serial.printf("Last Report: ");
Serial.println(lastReport);
#endif
if (lastReport == 0) {
#ifdef LOGSTUFF
Serial.println("lastReport is zero. Exiting.");
#endif
return;
}
#ifdef LOGSTUFF
Serial.println("lastReport is not zero. Continuing.");
#endif
Sensor.readRegister(&dataRead, 0x35); // Read INT2_SRC
#ifdef LOGSTUFF
Serial.print("Data read: ");
Serial.println(dataRead);
#endif
#ifdef LOGSTUFF
Serial.print("dataRead & 0x20 :");
Serial.println(dataRead & 0x20);
Serial.print("dataRead & 0x10 :");
Serial.println(dataRead & 0x10);
#endif
if (dataRead & 0x10) {
// Continue on with the loop
} else {
#ifdef LOGSTUFF
Serial.println("Not right status. Exiting.");
#endif
return;
}
lastMillis = currentMillis;
lastReport = 0;
uint16_t batt = (uint16_t)(api.system.bat.get() * 1000);
#ifdef LOGSTUFF
Serial.printf("battery %.2f\r\n", (float)batt);
Serial.printf("Battery Level: %f\r\n", api.system.bat.get());
#endif
/** Cayenne Low Power Payload */
uint8_t data_len = 0;
collected_data[data_len++] = 0x01; //Data Channel: 1 //1
collected_data[data_len++] = 0x00; //Type: Digital Input //2
collected_data[data_len++] = 0; //3
collected_data[data_len++] = 0x02; //Data Channel: 2 //4
collected_data[data_len++] = 0x02; //Type: Analog Input //5
collected_data[data_len++] = (uint8_t)(batt >> 8); //6
collected_data[data_len++] = (uint8_t)batt; //7
/** Send the data package */
if (api.lorawan.send(data_len, (uint8_t *) & collected_data, 2, false, 1)) {
#ifdef LOGSTUFF
Serial.println("Sending is requested");
#endif
} else {
#ifdef LOGSTUFF
Serial.println("Sending failed");
#endif
}
//api.system.sleep.all(deltaTimeReportMax);
}
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void loopTimerReport()
// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{
uint8_t dataRead;
currentMillis = millis();
uint8_t tiltStatus = 99;
#ifdef LOGSTUFF
Serial.println("\r\n");
Serial.println("---------------------------------------------------");
Serial.println("loopTimerReport report");
Serial.println("---------------------------------------------------");
Serial.printf("Current millis: ");
Serial.println(currentMillis);
Serial.printf("Last millis: ");
Serial.println(lastMillis);
Serial.printf("Last Report: ");
Serial.println(lastReport);
#endif
Sensor.readRegister(&dataRead, LIS3DH_INT1_SRC);
#ifdef LOGSTUFF
Serial.print("Data read: ");
Serial.println(dataRead);
#endif
#ifdef LOGSTUFF
Serial.print("dataRead & 0x20 :");
Serial.println(dataRead & 0x20);
Serial.print("dataRead & 0x10 :");
Serial.println(dataRead & 0x10);
#endif
if(dataRead & 0x20) tiltStatus = 0x01; // Serial.println("Z high");
if(dataRead & 0x10) tiltStatus = 0x00; // Serial.println("Z low");
#ifdef LOGSTUFF
Serial.print("New Tilt Status: ");
Serial.println(tiltStatus);
#endif
lastMillis = currentMillis;
lastReport = tiltStatus;
uint16_t batt = (uint16_t)(api.system.bat.get() * 1000);
#ifdef LOGSTUFF
Serial.printf("battery %.2f\r\n", (float)batt);
Serial.printf("Battery Level: %f\r\n", api.system.bat.get());
#endif
/** Cayenne Low Power Payload */
uint8_t data_len = 0;
collected_data[data_len++] = 0x01; //Data Channel: 1 //1
collected_data[data_len++] = 0x00; //Type: Digital Input //2
collected_data[data_len++] = tiltStatus; //3
collected_data[data_len++] = 0x02; //Data Channel: 2 //4
collected_data[data_len++] = 0x02; //Type: Analog Input //5
collected_data[data_len++] = (uint8_t)(batt >> 8); //6
collected_data[data_len++] = (uint8_t)batt; //7
/** Send the data package */
if (api.lorawan.send(data_len, (uint8_t *) & collected_data, 2, false, 1)) {
#ifdef LOGSTUFF
Serial.println("Sending is requested");
#endif
} else {
#ifdef LOGSTUFF
Serial.println("Sending failed");
#endif
}
}
void loop()
{
// Perform sensor read
loopTimerReport();
#ifdef LOGSTUFF
Serial.println("Going to long sleep.");
#endif
api.system.sleep.all(deltaTimeReportMax);
#ifdef LOGSTUFF
Serial.println("Timer Wakeup.\r\n");
#endif
}